Skip to content

Commit f375794

Browse files
authored
Merge pull request #28 from GitGuardian/ggueutier/add-secret-rotation-script
feat(secret-key): add secret key rotation script
2 parents b0b9141 + 8364d2e commit f375794

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ Below is a brief overview of the tools available in this repository:
1414
| [honeytoken-tools](./honeytoken-tools) | Script to disseminate honeytokens in your repositories via Pull Requests |
1515
| [team-mapping-github-gitguardian](./team-mapping-github-gitguardian) | An example script using the GitHub and GitGuardian APIs to map GitHub Teams and the repositories they own to GitGuardian Teams and their perimeters. |
1616
| [team-mapping-gitlab-gitguardian](./team-mapping-gitlab-gitguardian) | An example script using the Gitlab and GitGuardian APIs to map Gitlab Groups and the repositories they own to GitGuardian Teams and their perimeters. |
17+
| [secret-key-rotation](./secret-key-rotation) | Rotate the Database Encrytion Secret Key. |

secret-key-rotation/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Rotate the Django Secret Key
2+
3+
To rotate the secret key used to encrypt GitGuardian’s PostgreSQL database data, follow the procedure described in [GitGuardian’s public documentation](https://docs.gitguardian.com/self-hosting/security/database-security).
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
6+
fetch_secret_keys() {
7+
# Fetch secret keys using provided namespace
8+
secret_key=$(kubectl get secret "${namespace[@]}" $secret_name \
9+
-o jsonpath='{.data.DJANGO_SECRET_KEY}' | base64 --decode)
10+
encryption_keys=$(kubectl get secret "${namespace[@]}" $secret_name \
11+
-o jsonpath='{.data.ENCRYPTION_KEYS}' | base64 --decode)
12+
echo "Django secret key hash: $(echo -n "$secret_key" | md5)"
13+
if [ -z "$encryption_keys" ]; then echo "No encryption keys found, Django secret key is thus used for DB encryption"; fi
14+
for key in ${encryption_keys//,/ }; do # loop over comma separated
15+
echo "DB encryption key hash: $(echo -n "$key" | md5)"
16+
done
17+
}
18+
19+
rotate_secret_keys() {
20+
echo "Starting rotation of encryption keys in namespace ${namespace[1]}"
21+
echo "After deployment, this will invalidate all current user sessions, as well as password reset links"
22+
echo "Complete rotation will be done after completion of all rotation jobs in admin area"
23+
echo "Do you want to continue? [yN]" && read -r confirm && [[ "$confirm" == [yY] ]] || exit 1
24+
25+
backup=$(mktemp)
26+
kubectl kots get config --appslug $app_name "${namespace[@]}" --decrypt > "$backup"
27+
echo "Backup of KOTS config written to $backup"
28+
# Generate new django secret key
29+
new_django_key=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 50 )
30+
echo "Setting new key with hash $(echo -n "$new_django_key" | md5)"
31+
current_key=$(kubectl get secret "${namespace[@]}" $secret_name \
32+
-o jsonpath='{.data.DJANGO_SECRET_KEY}' | base64 --decode)
33+
current_encryption_keys=$(kubectl get secret "${namespace[@]}" $secret_name \
34+
-o jsonpath='{.data.ENCRYPTION_KEYS}' | base64 --decode)
35+
36+
# new encryption starts with new key, that will be used for re-encryption, then current key for fallback
37+
if [ -n "$current_encryption_keys" ]; then
38+
new_encryption_keys=$(echo -n "$new_django_key,$current_encryption_keys,$current_key")
39+
else
40+
new_encryption_keys=$(echo -n "$new_django_key,$current_key")
41+
fi
42+
config_values=$(mktemp)
43+
trap "rm -f $config_values" EXIT
44+
cat <<EOF > "$config_values"
45+
apiVersion: kots.io/v1beta1
46+
kind: ConfigValues
47+
spec:
48+
values:
49+
django_secret_key:
50+
value: $new_django_key
51+
db_encryption_keys:
52+
value: $new_encryption_keys
53+
EOF
54+
55+
# Set it directly in KOTS config values
56+
kubectl kots set config $app_name "${namespace[@]}" \
57+
--config-file "$config_values" --merge
58+
59+
echo "App configuration is updated with new keys"
60+
echo "Please go to the admin console and deploy the new version"
61+
echo "When completed, go to the admin area to perform the rotation of the database encrypted fields"
62+
echo "Do you want to launch admin console now? [yN]" && read -r launch
63+
[[ "$launch" == [yY] ]] && kubectl kots admin-console "${namespace[@]}"
64+
}
65+
66+
namespace=()
67+
68+
usage() {
69+
echo "GitGuardian secrets rotation"
70+
echo "Usage: $0 [--namespace NAMESPACE] (status|rotate)"
71+
exit 0
72+
}
73+
74+
# Parse command line options
75+
while [[ $# -gt 0 ]]
76+
do
77+
key="$1"
78+
case $key in
79+
--namespace|-n)
80+
namespace=( "--namespace" "$2" )
81+
shift # past argument
82+
shift # past value
83+
;;
84+
status)
85+
action=fetch_secret_keys
86+
shift # past argument
87+
;;
88+
rotate)
89+
action=rotate_secret_keys
90+
shift # past argument
91+
;;
92+
--help|-h|help)
93+
usage=1
94+
shift ;;
95+
*)
96+
# Unknown option
97+
echo "Unknown action: $key"
98+
;;
99+
esac
100+
done
101+
102+
[ -n "$usage" ] && usage
103+
if [ -z "$action" ] && [ -z "$usage" ]; then echo "No action specified"; exit 1; fi
104+
if [ -z "${namespace[*]}" ]; then echo "No namespace specified"; exit 1; fi
105+
106+
app_name=$(kubectl kots get apps "${namespace[@]}" | cut -d ' ' -f 1 | tail -n 1)
107+
108+
case "$app_name" in
109+
gitguardian-seal) # v1 legacy
110+
secret_name="gitguardian-env-variables" ;;
111+
gitguardian) # v2
112+
secret_name="gim-secrets" ;;
113+
*)
114+
echo "Unknown app name: $app_name" && exit 1 ;;
115+
esac
116+
117+
[ -n "$action" ] && eval "$action"

0 commit comments

Comments
 (0)