aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex <alex@adnab.me>2023-01-01 18:47:34 +0000
committerAlex <alex@adnab.me>2023-01-01 18:47:34 +0000
commit3847c081817d93e75ec9ef8d53d2961e13df74c3 (patch)
treebd820bfda887f355fe1e56f8a1418c9353c59eb2
parentad6db2f1c502898e92fe377510dcf58b2d5ce6c9 (diff)
parent0d8c6a2d45c7b6bbb86f2d4268423578f0995894 (diff)
downloadnixcfg-3847c081817d93e75ec9ef8d53d2961e13df74c3.tar.gz
nixcfg-3847c081817d93e75ec9ef8d53d2961e13df74c3.zip
Merge pull request 'updated version of secretmgr' (#5) from new-secretmgr into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/nixcfg/pulls/5
-rw-r--r--cluster/prod/app/backup/secrets.toml92
-rw-r--r--cluster/prod/app/backup/secrets/backup/consul/backup_aws_access_key_id1
-rw-r--r--cluster/prod/app/backup/secrets/backup/consul/backup_aws_secret_access_key1
-rw-r--r--cluster/prod/app/backup/secrets/backup/consul/backup_restic_password1
-rw-r--r--cluster/prod/app/backup/secrets/backup/consul/backup_restic_repository1
-rw-r--r--cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_access_key_id1
-rw-r--r--cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_secret_access_key1
-rw-r--r--cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_password1
-rw-r--r--cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_repository1
-rw-r--r--cluster/prod/app/backup/secrets/backup/id_ed255191
-rw-r--r--cluster/prod/app/backup/secrets/backup/id_ed25519.pub1
-rw-r--r--cluster/prod/app/backup/secrets/backup/psql/aws_access_key_id1
-rw-r--r--cluster/prod/app/backup/secrets/backup/psql/aws_secret_access_key1
-rw-r--r--cluster/prod/app/backup/secrets/backup/psql/crypt_private_key1
-rw-r--r--cluster/prod/app/backup/secrets/backup/psql/crypt_public_key1
-rw-r--r--cluster/prod/app/backup/secrets/backup/target_ssh_dir1
-rw-r--r--cluster/prod/app/backup/secrets/backup/target_ssh_fingerprint1
-rw-r--r--cluster/prod/app/backup/secrets/backup/target_ssh_host1
-rw-r--r--cluster/prod/app/backup/secrets/backup/target_ssh_port1
-rw-r--r--cluster/prod/app/backup/secrets/backup/target_ssh_user1
-rw-r--r--cluster/prod/app/core/secrets.toml5
-rw-r--r--cluster/prod/app/core/secrets/directory/ldap_base_dn1
-rw-r--r--cluster/prod/app/drone-ci/secrets.toml48
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/cookie_secret1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/db_enc_secret1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_id1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_secret1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/rpc_secret1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/s3_ak1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/s3_db_bucket1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/s3_sk1
-rw-r--r--cluster/prod/app/drone-ci/secrets/drone-ci/s3_storage_bucket1
-rwxr-xr-xcluster/prod/app/email/config/dovecot/certs.gen13
-rwxr-xr-xcluster/prod/app/email/config/postfix/certs.gen13
-rw-r--r--cluster/prod/app/email/deploy/email.hcl4
-rw-r--r--cluster/prod/app/email/secrets.toml23
-rw-r--r--cluster/prod/app/email/secrets/email/dkim/smtp.private1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/backup_aws_access_key_id1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/backup_aws_secret_access_key1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/backup_restic_password1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/backup_restic_repository1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/dovecot.crt1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/dovecot.key1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/ldap_binddn1
-rw-r--r--cluster/prod/app/email/secrets/email/dovecot/ldap_bindpwd1
-rw-r--r--cluster/prod/app/email/secrets/email/postfix/postfix.crt1
-rw-r--r--cluster/prod/app/email/secrets/email/postfix/postfix.key1
-rw-r--r--cluster/prod/app/email/secrets/email/sogo/ldap_binddn1
-rw-r--r--cluster/prod/app/email/secrets/email/sogo/ldap_bindpw1
-rw-r--r--cluster/prod/app/email/secrets/email/sogo/postgre_auth1
-rw-r--r--cluster/prod/app/garage/secrets.toml14
-rw-r--r--cluster/prod/app/garage/secrets/garage/admin_token1
-rw-r--r--cluster/prod/app/garage/secrets/garage/metrics_token1
-rw-r--r--cluster/prod/app/garage/secrets/garage/rpc_secret1
-rw-r--r--cluster/prod/app/guichet/secrets.toml51
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/mail_domain1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/mail_from1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/s3_access_key1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/s3_bucket1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/s3_endpoint1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/s3_region1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/s3_secret_key1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/smtp_pass1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/smtp_server1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/smtp_user1
-rw-r--r--cluster/prod/app/guichet/secrets/directory/guichet/web_hostname1
-rw-r--r--cluster/prod/app/jitsi/secrets.toml36
-rw-r--r--cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.crt1
-rw-r--r--cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.key1
-rw-r--r--cluster/prod/app/jitsi/secrets/jitsi/jicofo_pass1
-rw-r--r--cluster/prod/app/jitsi/secrets/jitsi/jitsi.crt1
-rw-r--r--cluster/prod/app/jitsi/secrets/jitsi/jitsi.key1
-rw-r--r--cluster/prod/app/jitsi/secrets/jitsi/jvb_pass1
-rw-r--r--cluster/prod/app/matrix/config/synapse/homeserver.yaml16
-rw-r--r--cluster/prod/app/matrix/deploy/im.hcl15
-rw-r--r--cluster/prod/app/matrix/secrets.toml81
-rw-r--r--cluster/prod/app/matrix/secrets/chat/coturn/static-auth1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/coturn/static_auth_secret_zinzdev1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/easybridge/as_token1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/easybridge/db_pass1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/easybridge/db_user1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/easybridge/hs_token1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/easybridge/web_session_key2
-rw-r--r--cluster/prod/app/matrix/secrets/chat/fb2mx/as_token1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/fb2mx/db_url1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/fb2mx/hs_token1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/homeserver.signing.key1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.crt1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.dh1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.key1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/ldap_binddn1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/ldap_bindpw1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/postgres_db1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/postgres_pwd1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/postgres_user1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/registration_shared_secret1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/s3_access_key1
-rw-r--r--cluster/prod/app/matrix/secrets/chat/synapse/s3_secret_key1
-rw-r--r--cluster/prod/app/plume/secrets.toml10
-rw-r--r--cluster/prod/app/plume/secrets/plume/backup_aws_access_key_id1
-rw-r--r--cluster/prod/app/plume/secrets/plume/backup_aws_secret_access_key1
-rw-r--r--cluster/prod/app/plume/secrets/plume/backup_restic_password1
-rw-r--r--cluster/prod/app/plume/secrets/plume/backup_restic_repository1
-rw-r--r--cluster/prod/app/plume/secrets/plume/pgsql_pw1
-rw-r--r--cluster/prod/app/plume/secrets/plume/secret_key1
-rw-r--r--cluster/prod/app/postgres/secrets.toml10
-rw-r--r--cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_pwd1
-rw-r--r--cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_username1
-rw-r--r--cluster/prod/app/postgres/secrets/postgres/keeper/pg_su_pwd1
l---------cluster/prod/app/secretmgr1
-rw-r--r--cluster/prod/app/telemetry/secrets.toml16
-rw-r--r--cluster/prod/app/telemetry/secrets/telemetry/grafana/admin_password1
-rw-r--r--cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_access_key1
-rw-r--r--cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_secret_key1
-rw-r--r--cluster/prod/secretmgr.toml19
l---------cluster/staging/app/convertsecrets1
-rw-r--r--cluster/staging/app/core/secrets.toml4
-rw-r--r--cluster/staging/app/core/secrets/d53/gandi_api_key1
-rw-r--r--cluster/staging/app/directory/secrets.toml51
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/mail_domain1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/mail_from1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/s3_access_key1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/s3_bucket1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/s3_endpoint1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/s3_region1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/s3_secret_key1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/smtp_pass1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/smtp_server1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/smtp_user1
-rw-r--r--cluster/staging/app/directory/secrets/directory/guichet/web_hostname1
-rw-r--r--cluster/staging/app/directory/secrets/directory/ldap_base_dn1
-rw-r--r--cluster/staging/app/dummy/secrets.toml36
-rw-r--r--cluster/staging/app/garage/secrets.toml15
-rw-r--r--cluster/staging/app/garage/secrets/garage-staging/admin_token1
-rw-r--r--cluster/staging/app/garage/secrets/garage-staging/metrics_token1
-rw-r--r--cluster/staging/app/garage/secrets/garage-staging/rpc_secret1
-rw-r--r--cluster/staging/app/im/secrets.toml27
-rw-r--r--cluster/staging/app/im/secrets/synapse/form_secret1
-rw-r--r--cluster/staging/app/im/secrets/synapse/macaroon_secret_key1
-rw-r--r--cluster/staging/app/im/secrets/synapse/registration_shared_secret1
-rw-r--r--cluster/staging/app/im/secrets/synapse/s3_access_key1
-rw-r--r--cluster/staging/app/im/secrets/synapse/s3_secret_key1
-rw-r--r--cluster/staging/app/im/secrets/synapse/signing_key1
l---------cluster/staging/app/secretmgr1
-rw-r--r--cluster/staging/app/telemetry/secrets.toml13
-rw-r--r--cluster/staging/app/telemetry/secrets/telemetry/grafana/admin_password1
-rw-r--r--cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_access_key1
-rw-r--r--cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_secret_key1
-rw-r--r--cluster/staging/secretmgr.toml19
-rwxr-xr-xsecretmgr576
-rwxr-xr-xsecretmgr/secretmgr382
151 files changed, 1147 insertions, 568 deletions
diff --git a/cluster/prod/app/backup/secrets.toml b/cluster/prod/app/backup/secrets.toml
new file mode 100644
index 0000000..91794ae
--- /dev/null
+++ b/cluster/prod/app/backup/secrets.toml
@@ -0,0 +1,92 @@
+# Cryptpad backup
+
+[secrets."backup/cryptpad/backup_restic_password"]
+type = 'user'
+description = 'Restic password to encrypt backups'
+
+[secrets."backup/cryptpad/backup_aws_secret_access_key"]
+type = 'user'
+description = 'Backup AWS secret access key'
+
+[secrets."backup/cryptpad/backup_restic_repository"]
+type = 'user'
+description = 'Restic repository'
+example = 's3:https://s3.garage.tld'
+
+[secrets."backup/cryptpad/backup_aws_access_key_id"]
+type = 'user'
+description = 'Backup AWS access key ID'
+
+
+# Consul backup
+
+[secrets."backup/consul/backup_restic_password"]
+type = 'user'
+description = 'Restic password to encrypt backups'
+
+[secrets."backup/consul/backup_aws_secret_access_key"]
+type = 'user'
+description = 'Backup AWS secret access key'
+
+[secrets."backup/consul/backup_restic_repository"]
+type = 'user'
+description = 'Restic repository'
+example = 's3:https://s3.garage.tld'
+
+[secrets."backup/consul/backup_aws_access_key_id"]
+type = 'user'
+description = 'Backup AWS access key ID'
+
+
+# Postgresql backup
+
+[secrets."postgres/backup/aws_access_key_id"]
+type = 'user'
+description = 'Minio access key'
+
+[secrets."postgres/backup/aws_secret_access_key"]
+type = 'user'
+description = 'Minio secret key'
+
+[secrets."postgres/backup/crypt_public_key"]
+type = 'user'
+description = 'A public key to encypt backups with age'
+
+
+# Plume backup
+
+[secrets."plume/backup_restic_repository"]
+type = 'user'
+description = 'Restic repository'
+example = 's3:https://s3.garage.tld'
+
+[secrets."plume/backup_restic_password"]
+type = 'user'
+description = 'Restic password to encrypt backups'
+
+[secrets."plume/backup_aws_secret_access_key"]
+type = 'user'
+description = 'Backup AWS secret access key'
+
+[secrets."plume/backup_aws_access_key_id"]
+type = 'user'
+description = 'Backup AWS access key ID'
+
+
+# Dovecot backup
+
+[secrets."email/dovecot/backup_restic_password"]
+type = 'user'
+description = 'Restic backup password to encrypt data'
+
+[secrets."email/dovecot/backup_aws_secret_access_key"]
+type = 'user'
+description = 'AWS Secret Access key'
+
+[secrets."email/dovecot/backup_restic_repository"]
+type = 'user'
+description = 'Restic Repository URL, check op_guide/backup-minio to see the format'
+
+[secrets."email/dovecot/backup_aws_access_key_id"]
+type = 'user'
+description = 'AWS Acces Key ID'
diff --git a/cluster/prod/app/backup/secrets/backup/consul/backup_aws_access_key_id b/cluster/prod/app/backup/secrets/backup/consul/backup_aws_access_key_id
deleted file mode 100644
index 9235e53..0000000
--- a/cluster/prod/app/backup/secrets/backup/consul/backup_aws_access_key_id
+++ /dev/null
@@ -1 +0,0 @@
-USER Backup AWS access key ID
diff --git a/cluster/prod/app/backup/secrets/backup/consul/backup_aws_secret_access_key b/cluster/prod/app/backup/secrets/backup/consul/backup_aws_secret_access_key
deleted file mode 100644
index f34677e..0000000
--- a/cluster/prod/app/backup/secrets/backup/consul/backup_aws_secret_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Backup AWS secret access key
diff --git a/cluster/prod/app/backup/secrets/backup/consul/backup_restic_password b/cluster/prod/app/backup/secrets/backup/consul/backup_restic_password
deleted file mode 100644
index fbaa5fa..0000000
--- a/cluster/prod/app/backup/secrets/backup/consul/backup_restic_password
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic password to encrypt backups
diff --git a/cluster/prod/app/backup/secrets/backup/consul/backup_restic_repository b/cluster/prod/app/backup/secrets/backup/consul/backup_restic_repository
deleted file mode 100644
index 3f6cb93..0000000
--- a/cluster/prod/app/backup/secrets/backup/consul/backup_restic_repository
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic repository, eg. s3:https://s3.garage.tld
diff --git a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_access_key_id b/cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_access_key_id
deleted file mode 100644
index 9235e53..0000000
--- a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_access_key_id
+++ /dev/null
@@ -1 +0,0 @@
-USER Backup AWS access key ID
diff --git a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_secret_access_key b/cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_secret_access_key
deleted file mode 100644
index f34677e..0000000
--- a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_aws_secret_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Backup AWS secret access key
diff --git a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_password b/cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_password
deleted file mode 100644
index fbaa5fa..0000000
--- a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_password
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic password to encrypt backups
diff --git a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_repository b/cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_repository
deleted file mode 100644
index 3f6cb93..0000000
--- a/cluster/prod/app/backup/secrets/backup/cryptpad/backup_restic_repository
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic repository, eg. s3:https://s3.garage.tld
diff --git a/cluster/prod/app/backup/secrets/backup/id_ed25519 b/cluster/prod/app/backup/secrets/backup/id_ed25519
deleted file mode 100644
index 9d7fd46..0000000
--- a/cluster/prod/app/backup/secrets/backup/id_ed25519
+++ /dev/null
@@ -1 +0,0 @@
-USER_LONG Private ed25519 key of the container doing the backup
diff --git a/cluster/prod/app/backup/secrets/backup/id_ed25519.pub b/cluster/prod/app/backup/secrets/backup/id_ed25519.pub
deleted file mode 100644
index 0a2ab35..0000000
--- a/cluster/prod/app/backup/secrets/backup/id_ed25519.pub
+++ /dev/null
@@ -1 +0,0 @@
-USER Public ed25519 key of the container doing the backup (this key must be in authorized_keys on the backup target host)
diff --git a/cluster/prod/app/backup/secrets/backup/psql/aws_access_key_id b/cluster/prod/app/backup/secrets/backup/psql/aws_access_key_id
deleted file mode 100644
index 82375d7..0000000
--- a/cluster/prod/app/backup/secrets/backup/psql/aws_access_key_id
+++ /dev/null
@@ -1 +0,0 @@
-USER Minio access key
diff --git a/cluster/prod/app/backup/secrets/backup/psql/aws_secret_access_key b/cluster/prod/app/backup/secrets/backup/psql/aws_secret_access_key
deleted file mode 100644
index de5090c..0000000
--- a/cluster/prod/app/backup/secrets/backup/psql/aws_secret_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Minio secret key
diff --git a/cluster/prod/app/backup/secrets/backup/psql/crypt_private_key b/cluster/prod/app/backup/secrets/backup/psql/crypt_private_key
deleted file mode 100644
index 4abece9..0000000
--- a/cluster/prod/app/backup/secrets/backup/psql/crypt_private_key
+++ /dev/null
@@ -1 +0,0 @@
-USER a private key to decript backups from age
diff --git a/cluster/prod/app/backup/secrets/backup/psql/crypt_public_key b/cluster/prod/app/backup/secrets/backup/psql/crypt_public_key
deleted file mode 100644
index 156ad47..0000000
--- a/cluster/prod/app/backup/secrets/backup/psql/crypt_public_key
+++ /dev/null
@@ -1 +0,0 @@
-USER A public key to encypt backups with age
diff --git a/cluster/prod/app/backup/secrets/backup/target_ssh_dir b/cluster/prod/app/backup/secrets/backup/target_ssh_dir
deleted file mode 100644
index 3b2a4da..0000000
--- a/cluster/prod/app/backup/secrets/backup/target_ssh_dir
+++ /dev/null
@@ -1 +0,0 @@
-USER Directory where to store backups on target host
diff --git a/cluster/prod/app/backup/secrets/backup/target_ssh_fingerprint b/cluster/prod/app/backup/secrets/backup/target_ssh_fingerprint
deleted file mode 100644
index 608f3ec..0000000
--- a/cluster/prod/app/backup/secrets/backup/target_ssh_fingerprint
+++ /dev/null
@@ -1 +0,0 @@
-USER SSH fingerprint of the target machine (format: copy here the corresponding line from your known_hosts file)
diff --git a/cluster/prod/app/backup/secrets/backup/target_ssh_host b/cluster/prod/app/backup/secrets/backup/target_ssh_host
deleted file mode 100644
index 6268f87..0000000
--- a/cluster/prod/app/backup/secrets/backup/target_ssh_host
+++ /dev/null
@@ -1 +0,0 @@
-USER Hostname of the backup target host
diff --git a/cluster/prod/app/backup/secrets/backup/target_ssh_port b/cluster/prod/app/backup/secrets/backup/target_ssh_port
deleted file mode 100644
index 309dd38..0000000
--- a/cluster/prod/app/backup/secrets/backup/target_ssh_port
+++ /dev/null
@@ -1 +0,0 @@
-USER SSH port number to connect to the target host
diff --git a/cluster/prod/app/backup/secrets/backup/target_ssh_user b/cluster/prod/app/backup/secrets/backup/target_ssh_user
deleted file mode 100644
index 98b3046..0000000
--- a/cluster/prod/app/backup/secrets/backup/target_ssh_user
+++ /dev/null
@@ -1 +0,0 @@
-USER SSH username to log in as on the target host
diff --git a/cluster/prod/app/core/secrets.toml b/cluster/prod/app/core/secrets.toml
new file mode 100644
index 0000000..736c9dd
--- /dev/null
+++ b/cluster/prod/app/core/secrets.toml
@@ -0,0 +1,5 @@
+[secrets."directory/ldap_base_dn"]
+type = 'user'
+description = 'LDAP base DN for everything'
+example = 'dc=example,dc=com'
+
diff --git a/cluster/prod/app/core/secrets/directory/ldap_base_dn b/cluster/prod/app/core/secrets/directory/ldap_base_dn
deleted file mode 100644
index ea5c7ae..0000000
--- a/cluster/prod/app/core/secrets/directory/ldap_base_dn
+++ /dev/null
@@ -1 +0,0 @@
-USER LDAP base DN for everything (e.g. dc=example,dc=com)
diff --git a/cluster/prod/app/drone-ci/secrets.toml b/cluster/prod/app/drone-ci/secrets.toml
new file mode 100644
index 0000000..ac07926
--- /dev/null
+++ b/cluster/prod/app/drone-ci/secrets.toml
@@ -0,0 +1,48 @@
+# Drone's secrets
+
+[secrets."drone-ci/rpc_secret"]
+type = 'command'
+command = 'openssl rand -hex 16'
+# don't rotate, it would break all runners
+
+[secrets."drone-ci/cookie_secret"]
+type = 'command'
+rotate = true
+command = 'openssl rand -hex 16'
+
+[secrets."drone-ci/db_enc_secret"]
+type = 'command'
+command = 'openssl rand -hex 16'
+# don't rotate, it is used to encrypt data which we would lose if we change this
+
+
+# Oauth config for gitea
+
+[secrets."drone-ci/oauth_client_secret"]
+type = 'user'
+description = 'OAuth client secret (for gitea)'
+
+[secrets."drone-ci/oauth_client_id"]
+type = 'user'
+description = 'OAuth client ID (on Gitea)'
+
+
+# S3 config for Git LFS storage
+
+[secrets."drone-ci/s3_db_bucket"]
+type = 'constant'
+value = 'drone-db'
+
+[secrets."drone-ci/s3_sk"]
+type = 'user'
+description = 'S3 (garage) secret key for Drone'
+
+[secrets."drone-ci/s3_ak"]
+type = 'user'
+description = 'S3 (garage) access key for Drone'
+
+[secrets."drone-ci/s3_storage_bucket"]
+type = 'constant'
+value = 'drone-storage'
+
+
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/cookie_secret b/cluster/prod/app/drone-ci/secrets/drone-ci/cookie_secret
deleted file mode 100644
index 04c819e..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/cookie_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 16
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/db_enc_secret b/cluster/prod/app/drone-ci/secrets/drone-ci/db_enc_secret
deleted file mode 100644
index 3f9e696..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/db_enc_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD_ONCE openssl rand -hex 16
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_id b/cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_id
deleted file mode 100644
index c801b28..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_id
+++ /dev/null
@@ -1 +0,0 @@
-USER OAuth client ID (on Gitea)
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_secret b/cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_secret
deleted file mode 100644
index b79b688..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/oauth_client_secret
+++ /dev/null
@@ -1 +0,0 @@
-USER OAuth client secret (for gitea)
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/rpc_secret b/cluster/prod/app/drone-ci/secrets/drone-ci/rpc_secret
deleted file mode 100644
index 04c819e..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/rpc_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 16
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_ak b/cluster/prod/app/drone-ci/secrets/drone-ci/s3_ak
deleted file mode 100644
index 3a8e4a2..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_ak
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 (garage) access key for Drone
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_db_bucket b/cluster/prod/app/drone-ci/secrets/drone-ci/s3_db_bucket
deleted file mode 100644
index c36f17d..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_db_bucket
+++ /dev/null
@@ -1 +0,0 @@
-CONST drone-db
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_sk b/cluster/prod/app/drone-ci/secrets/drone-ci/s3_sk
deleted file mode 100644
index 46fd9fa..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_sk
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 (garage) secret key for Drone
diff --git a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_storage_bucket b/cluster/prod/app/drone-ci/secrets/drone-ci/s3_storage_bucket
deleted file mode 100644
index ca2702c..0000000
--- a/cluster/prod/app/drone-ci/secrets/drone-ci/s3_storage_bucket
+++ /dev/null
@@ -1 +0,0 @@
-CONST drone-storage
diff --git a/cluster/prod/app/email/config/dovecot/certs.gen b/cluster/prod/app/email/config/dovecot/certs.gen
deleted file mode 100755
index f26e917..0000000
--- a/cluster/prod/app/email/config/dovecot/certs.gen
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-TLSINFO="/C=FR/ST=Bretagne/L=Rennes/O=Deuxfleurs/CN=imap.deuxfleurs.fr"
-openssl req \
- -new \
- -newkey rsa:4096 \
- -days 3650 \
- -nodes \
- -x509 \
- -subj ${TLSINFO} \
- -keyout dovecot.key \
- -out dovecot.crt
-
diff --git a/cluster/prod/app/email/config/postfix/certs.gen b/cluster/prod/app/email/config/postfix/certs.gen
deleted file mode 100755
index f25439b..0000000
--- a/cluster/prod/app/email/config/postfix/certs.gen
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-TLSINFO="/C=FR/ST=Bretagne/L=Rennes/O=Deuxfleurs/CN=smtp.deuxfleurs.fr"
-openssl req \
- -new \
- -newkey rsa:4096 \
- -days 3650 \
- -nodes \
- -x509 \
- -subj ${TLSINFO} \
- -keyout postfix.key \
- -out postfix.crt
-
diff --git a/cluster/prod/app/email/deploy/email.hcl b/cluster/prod/app/email/deploy/email.hcl
index 7925975..84f4c3b 100644
--- a/cluster/prod/app/email/deploy/email.hcl
+++ b/cluster/prod/app/email/deploy/email.hcl
@@ -150,13 +150,11 @@ job "email" {
# ----- secrets ------
template {
- # data = "{{ key \"secrets/email/dovecot/dovecot.crt\" }}"
data = "{{ with $d := key \"tricot/certs/imap.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}"
destination = "secrets/ssl/certs/dovecot.crt"
perms = "400"
}
template {
- # data = "{{ key \"secrets/email/dovecot/dovecot.key\" }}"
data = "{{ with $d := key \"tricot/certs/imap.deuxfleurs.fr\" | parseJSON }}{{ $d.key_pem }}{{ end }}"
destination = "secrets/ssl/private/dovecot.key"
perms = "400"
@@ -381,14 +379,12 @@ job "email" {
# --- secrets ---
template {
- # data = "{{ key \"secrets/email/postfix/postfix.crt\" }}"
data = "{{ with $d := key \"tricot/certs/smtp.deuxfleurs.fr\" | parseJSON }}{{ $d.cert_pem }}{{ end }}"
destination = "secrets/ssl/postfix.crt"
perms = "400"
}
template {
- # data = "{{ key \"secrets/email/postfix/postfix.key\" }}"
data = "{{ with $d := key \"tricot/certs/smtp.deuxfleurs.fr\" | parseJSON }}{{ $d.key_pem }}{{ end }}"
destination = "secrets/ssl/postfix.key"
perms = "400"
diff --git a/cluster/prod/app/email/secrets.toml b/cluster/prod/app/email/secrets.toml
new file mode 100644
index 0000000..6263e33
--- /dev/null
+++ b/cluster/prod/app/email/secrets.toml
@@ -0,0 +1,23 @@
+# ---- POSTFIX ----
+
+[secrets."email/dkim/smtp.private"]
+type = 'RSA_PRIVATE_KEY'
+name = 'dkim'
+
+# ---- DOVECOT ----
+
+[service_users."dovecot"]
+dn_secret = "email/dovecot/ldap_binddn"
+password_secret = "email/dovecot/ldap_bindpwd"
+
+
+# ---- SOGO ----
+
+[service_users."sogo"]
+dn_secret = "email/sogo/ldap_binddn"
+password_secret = "email/sogo/ldap_bindpw"
+
+[secrets."email/sogo/postgre_auth"]
+type = 'user'
+description = 'SoGo postgres auth (format: sogo:<password>) (TODO: replace this with two separate files and change template)'
+
diff --git a/cluster/prod/app/email/secrets/email/dkim/smtp.private b/cluster/prod/app/email/secrets/email/dkim/smtp.private
deleted file mode 100644
index 3aa3621..0000000
--- a/cluster/prod/app/email/secrets/email/dkim/smtp.private
+++ /dev/null
@@ -1 +0,0 @@
-RSA_PRIVATE_KEY dkim
diff --git a/cluster/prod/app/email/secrets/email/dovecot/backup_aws_access_key_id b/cluster/prod/app/email/secrets/email/dovecot/backup_aws_access_key_id
deleted file mode 100644
index 9ae6adf..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/backup_aws_access_key_id
+++ /dev/null
@@ -1 +0,0 @@
-USER AWS Acces Key ID
diff --git a/cluster/prod/app/email/secrets/email/dovecot/backup_aws_secret_access_key b/cluster/prod/app/email/secrets/email/dovecot/backup_aws_secret_access_key
deleted file mode 100644
index ac95906..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/backup_aws_secret_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER AWS Secret Access key
diff --git a/cluster/prod/app/email/secrets/email/dovecot/backup_restic_password b/cluster/prod/app/email/secrets/email/dovecot/backup_restic_password
deleted file mode 100644
index c19a4a3..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/backup_restic_password
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic backup password to encrypt data
diff --git a/cluster/prod/app/email/secrets/email/dovecot/backup_restic_repository b/cluster/prod/app/email/secrets/email/dovecot/backup_restic_repository
deleted file mode 100644
index 0434a15..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/backup_restic_repository
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic Repository URL, check op_guide/backup-minio to see the format
diff --git a/cluster/prod/app/email/secrets/email/dovecot/dovecot.crt b/cluster/prod/app/email/secrets/email/dovecot/dovecot.crt
deleted file mode 100644
index 7229cfc..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/dovecot.crt
+++ /dev/null
@@ -1 +0,0 @@
-SSL_CERT dovecot deuxfleurs.fr
diff --git a/cluster/prod/app/email/secrets/email/dovecot/dovecot.key b/cluster/prod/app/email/secrets/email/dovecot/dovecot.key
deleted file mode 100644
index 0d42c79..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/dovecot.key
+++ /dev/null
@@ -1 +0,0 @@
-SSL_KEY dovecot
diff --git a/cluster/prod/app/email/secrets/email/dovecot/ldap_binddn b/cluster/prod/app/email/secrets/email/dovecot/ldap_binddn
deleted file mode 100644
index da380f2..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/ldap_binddn
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_DN dovecot Dovecot IMAP server
diff --git a/cluster/prod/app/email/secrets/email/dovecot/ldap_bindpwd b/cluster/prod/app/email/secrets/email/dovecot/ldap_bindpwd
deleted file mode 100644
index 068f663..0000000
--- a/cluster/prod/app/email/secrets/email/dovecot/ldap_bindpwd
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_PASSWORD dovecot
diff --git a/cluster/prod/app/email/secrets/email/postfix/postfix.crt b/cluster/prod/app/email/secrets/email/postfix/postfix.crt
deleted file mode 100644
index f004d67..0000000
--- a/cluster/prod/app/email/secrets/email/postfix/postfix.crt
+++ /dev/null
@@ -1 +0,0 @@
-SSL_CERT postfix deuxfleurs.fr
diff --git a/cluster/prod/app/email/secrets/email/postfix/postfix.key b/cluster/prod/app/email/secrets/email/postfix/postfix.key
deleted file mode 100644
index 2cf1706..0000000
--- a/cluster/prod/app/email/secrets/email/postfix/postfix.key
+++ /dev/null
@@ -1 +0,0 @@
-SSL_KEY postfix
diff --git a/cluster/prod/app/email/secrets/email/sogo/ldap_binddn b/cluster/prod/app/email/secrets/email/sogo/ldap_binddn
deleted file mode 100644
index df627d3..0000000
--- a/cluster/prod/app/email/secrets/email/sogo/ldap_binddn
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_DN sogo SoGo email frontend
diff --git a/cluster/prod/app/email/secrets/email/sogo/ldap_bindpw b/cluster/prod/app/email/secrets/email/sogo/ldap_bindpw
deleted file mode 100644
index 8d2f35b..0000000
--- a/cluster/prod/app/email/secrets/email/sogo/ldap_bindpw
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_PASSWORD sogo
diff --git a/cluster/prod/app/email/secrets/email/sogo/postgre_auth b/cluster/prod/app/email/secrets/email/sogo/postgre_auth
deleted file mode 100644
index 4f66253..0000000
--- a/cluster/prod/app/email/secrets/email/sogo/postgre_auth
+++ /dev/null
@@ -1 +0,0 @@
-USER SoGo postgres auth (format: sogo:<password>) (TODO: replace this with two separate files and change template)
diff --git a/cluster/prod/app/garage/secrets.toml b/cluster/prod/app/garage/secrets.toml
new file mode 100644
index 0000000..e616091
--- /dev/null
+++ b/cluster/prod/app/garage/secrets.toml
@@ -0,0 +1,14 @@
+[secrets."garage/rpc_secret"]
+type = 'command'
+command = 'openssl rand -hex 32'
+# can't auto-rotate, because we still have some nodes outside of Nomad
+
+[secrets."garage/admin_token"]
+type = 'command'
+command = 'openssl rand -hex 32'
+rotate = true
+
+[secrets."garage/metrics_token"]
+type = 'command'
+command = 'openssl rand -hex 32'
+rotate = true
diff --git a/cluster/prod/app/garage/secrets/garage/admin_token b/cluster/prod/app/garage/secrets/garage/admin_token
deleted file mode 100644
index d831d53..0000000
--- a/cluster/prod/app/garage/secrets/garage/admin_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD_ONCE openssl rand -hex 32
diff --git a/cluster/prod/app/garage/secrets/garage/metrics_token b/cluster/prod/app/garage/secrets/garage/metrics_token
deleted file mode 100644
index d831d53..0000000
--- a/cluster/prod/app/garage/secrets/garage/metrics_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD_ONCE openssl rand -hex 32
diff --git a/cluster/prod/app/garage/secrets/garage/rpc_secret b/cluster/prod/app/garage/secrets/garage/rpc_secret
deleted file mode 100644
index d831d53..0000000
--- a/cluster/prod/app/garage/secrets/garage/rpc_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD_ONCE openssl rand -hex 32
diff --git a/cluster/prod/app/guichet/secrets.toml b/cluster/prod/app/guichet/secrets.toml
new file mode 100644
index 0000000..d614b27
--- /dev/null
+++ b/cluster/prod/app/guichet/secrets.toml
@@ -0,0 +1,51 @@
+# General configuration
+
+[secrets."directory/guichet/web_hostname"]
+type = 'user'
+description = 'Public hostname from which Guichet is accessible via HTTP (e.g. guichet.example.com)'
+
+
+# Mailing configuration
+
+[secrets."directory/guichet/smtp_user"]
+type = 'user'
+description = 'SMTP username'
+
+[secrets."directory/guichet/smtp_pass"]
+type = 'user'
+description = 'SMTP password'
+
+[secrets."directory/guichet/smtp_server"]
+type = 'user'
+description = 'SMTP server address (hostname:port)'
+
+[secrets."directory/guichet/mail_from"]
+type = 'user'
+description = 'E-mail address from which to send welcome emails to new users'
+
+[secrets."directory/guichet/mail_domain"]
+type = 'user'
+description = 'E-mail domain for new users (e.g. example.com)'
+
+
+# S3 configuration
+
+[secrets."directory/guichet/s3_endpoint"]
+type = 'user'
+description = 'S3 endpoint URL'
+
+[secrets."directory/guichet/s3_bucket"]
+type = 'user'
+description = 'S3 bucket in which to store data files (such as profile pictures)'
+
+[secrets."directory/guichet/s3_region"]
+type = 'user'
+description = 'S3 region'
+
+[secrets."directory/guichet/s3_access_key"]
+type = 'user'
+description = 'Garage access key for Guichet profile pictures'
+
+[secrets."directory/guichet/s3_secret_key"]
+type = 'user'
+description = 'Garage secret key for Guichet profile pictures'
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/mail_domain b/cluster/prod/app/guichet/secrets/directory/guichet/mail_domain
deleted file mode 100644
index 5db1ba3..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/mail_domain
+++ /dev/null
@@ -1 +0,0 @@
-USER E-mail domain for new users (e.g. example.com)
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/mail_from b/cluster/prod/app/guichet/secrets/directory/guichet/mail_from
deleted file mode 100644
index 9075cbf..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/mail_from
+++ /dev/null
@@ -1 +0,0 @@
-USER E-mail address from which to send welcome emails to new users
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/s3_access_key b/cluster/prod/app/guichet/secrets/directory/guichet/s3_access_key
deleted file mode 100644
index e5b37ff..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/s3_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Garage access key for Guichet profile pictures
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/s3_bucket b/cluster/prod/app/guichet/secrets/directory/guichet/s3_bucket
deleted file mode 100644
index cb059cf..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/s3_bucket
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 bucket in which to store data files (such as profile pictures)
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/s3_endpoint b/cluster/prod/app/guichet/secrets/directory/guichet/s3_endpoint
deleted file mode 100644
index b414269..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/s3_endpoint
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 endpoint URL
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/s3_region b/cluster/prod/app/guichet/secrets/directory/guichet/s3_region
deleted file mode 100644
index ef16924..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/s3_region
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 region
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/s3_secret_key b/cluster/prod/app/guichet/secrets/directory/guichet/s3_secret_key
deleted file mode 100644
index f3e7f0f..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/s3_secret_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Garage secret key for Guichet profile pictures
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/smtp_pass b/cluster/prod/app/guichet/secrets/directory/guichet/smtp_pass
deleted file mode 100644
index fc9d1e3..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/smtp_pass
+++ /dev/null
@@ -1 +0,0 @@
-USER SMTP password
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/smtp_server b/cluster/prod/app/guichet/secrets/directory/guichet/smtp_server
deleted file mode 100644
index c453935..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/smtp_server
+++ /dev/null
@@ -1 +0,0 @@
-USER SMTP server address (hostname:port)
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/smtp_user b/cluster/prod/app/guichet/secrets/directory/guichet/smtp_user
deleted file mode 100644
index c9c8bd0..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/smtp_user
+++ /dev/null
@@ -1 +0,0 @@
-USER SMTP username
diff --git a/cluster/prod/app/guichet/secrets/directory/guichet/web_hostname b/cluster/prod/app/guichet/secrets/directory/guichet/web_hostname
deleted file mode 100644
index afe2512..0000000
--- a/cluster/prod/app/guichet/secrets/directory/guichet/web_hostname
+++ /dev/null
@@ -1 +0,0 @@
-USER Public hostname from which Guichet is accessible via HTTP (e.g. guichet.example.com)
diff --git a/cluster/prod/app/jitsi/secrets.toml b/cluster/prod/app/jitsi/secrets.toml
new file mode 100644
index 0000000..cb6126f
--- /dev/null
+++ b/cluster/prod/app/jitsi/secrets.toml
@@ -0,0 +1,36 @@
+# Jitsi secrets
+
+[secrets."jitsi/jvb_pass"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 24'
+
+[secrets."jitsi/jicofo_pass"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 24'
+
+
+# SSL: Jitsi
+
+[secrets."jitsi/jitsi.crt"]
+type = 'SSL_CERT'
+name = 'jitsi'
+cert_domains = "['jitsi']"
+
+[secrets."jitsi/jitsi.key"]
+type = 'SSL_KEY'
+name = 'jitsi'
+
+
+# SSL: Jitsi auth
+
+[secrets."jitsi/auth.jitsi.crt"]
+type = 'SSL_CERT'
+name = 'jitsi_auth'
+cert_domains = "['auth.jitsi']"
+
+[secrets."jitsi/auth.jitsi.key"]
+type = 'SSL_KEY'
+name = 'jitsi_auth'
+
diff --git a/cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.crt b/cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.crt
deleted file mode 100644
index f4ab925..0000000
--- a/cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.crt
+++ /dev/null
@@ -1 +0,0 @@
-SSL_CERT jitsi_auth auth.jitsi
diff --git a/cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.key b/cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.key
deleted file mode 100644
index 82e7b6b..0000000
--- a/cluster/prod/app/jitsi/secrets/jitsi/auth.jitsi.key
+++ /dev/null
@@ -1 +0,0 @@
-SSL_KEY jitsi_auth auth.jitsi
diff --git a/cluster/prod/app/jitsi/secrets/jitsi/jicofo_pass b/cluster/prod/app/jitsi/secrets/jitsi/jicofo_pass
deleted file mode 100644
index 6a0f5fc..0000000
--- a/cluster/prod/app/jitsi/secrets/jitsi/jicofo_pass
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 24
diff --git a/cluster/prod/app/jitsi/secrets/jitsi/jitsi.crt b/cluster/prod/app/jitsi/secrets/jitsi/jitsi.crt
deleted file mode 100644
index 2eed97c..0000000
--- a/cluster/prod/app/jitsi/secrets/jitsi/jitsi.crt
+++ /dev/null
@@ -1 +0,0 @@
-SSL_CERT jitsi jitsi
diff --git a/cluster/prod/app/jitsi/secrets/jitsi/jitsi.key b/cluster/prod/app/jitsi/secrets/jitsi/jitsi.key
deleted file mode 100644
index af53ca0..0000000
--- a/cluster/prod/app/jitsi/secrets/jitsi/jitsi.key
+++ /dev/null
@@ -1 +0,0 @@
-SSL_KEY jitsi jitsi
diff --git a/cluster/prod/app/jitsi/secrets/jitsi/jvb_pass b/cluster/prod/app/jitsi/secrets/jitsi/jvb_pass
deleted file mode 100644
index 6a0f5fc..0000000
--- a/cluster/prod/app/jitsi/secrets/jitsi/jvb_pass
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 24
diff --git a/cluster/prod/app/matrix/config/synapse/homeserver.yaml b/cluster/prod/app/matrix/config/synapse/homeserver.yaml
index b4b7c67..48ae431 100644
--- a/cluster/prod/app/matrix/config/synapse/homeserver.yaml
+++ b/cluster/prod/app/matrix/config/synapse/homeserver.yaml
@@ -1,22 +1,6 @@
# vim:ft=yaml
server_name: "deuxfleurs.fr"
-# PEM encoded X509 certificate for TLS.
-# You can replace the self-signed certificate that synapse
-# autogenerates on launch with your own SSL certificate + key pair
-# if you like. Any required intermediary certificates can be
-# appended after the primary certificate in hierarchical order.
-tls_certificate_path: "/etc/matrix-synapse/homeserver.tls.crt"
-
-# PEM encoded private key for TLS
-tls_private_key_path: "/etc/matrix-synapse/homeserver.tls.key"
-
-# PEM dh parameters for ephemeral keys
-tls_dh_params_path: "/etc/matrix-synapse/homeserver.tls.dh"
-
-# Don't bind to the https port
-no_tls: True
-
## Server ##
diff --git a/cluster/prod/app/matrix/deploy/im.hcl b/cluster/prod/app/matrix/deploy/im.hcl
index bd28feb..339fea7 100644
--- a/cluster/prod/app/matrix/deploy/im.hcl
+++ b/cluster/prod/app/matrix/deploy/im.hcl
@@ -55,21 +55,6 @@ job "matrix" {
# --- secrets ---
template {
- data = "{{ key \"secrets/chat/synapse/homeserver.tls.crt\" }}"
- destination = "secrets/conf/homeserver.tls.crt"
- }
-
- template {
- data = "{{ key \"secrets/chat/synapse/homeserver.tls.dh\" }}"
- destination = "secrets/conf/homeserver.tls.dh"
- }
-
- template {
- data = "{{ key \"secrets/chat/synapse/homeserver.tls.key\" }}"
- destination = "secrets/conf/homeserver.tls.key"
- }
-
- template {
data = "{{ key \"secrets/chat/synapse/homeserver.signing.key\" }}"
destination = "secrets/conf/homeserver.signing.key"
}
diff --git a/cluster/prod/app/matrix/secrets.toml b/cluster/prod/app/matrix/secrets.toml
new file mode 100644
index 0000000..8cd1572
--- /dev/null
+++ b/cluster/prod/app/matrix/secrets.toml
@@ -0,0 +1,81 @@
+[service_users."matrix"]
+description = 'Matrix service user'
+dn_secret = 'chat/synapse/ldap_binddn'
+password_secret = 'chat/synapse/ldap_bindpw'
+
+
+# Postgresql DB
+
+[secrets."chat/synapse/postgres_db"]
+type = 'user'
+description = 'Synapse PostgrSQL database name'
+example = 'synapse'
+
+[secrets."chat/synapse/postgres_user"]
+type = 'service_username'
+service = 'matrix'
+
+[secrets."chat/synapse/postgres_pwd"]
+type = 'service_password'
+service = 'matrix'
+
+
+# S3 access
+
+[secrets."chat/synapse/s3_access_key"]
+type = 'user'
+description = 'S3 access key ID for Matrix bucket'
+
+[secrets."chat/synapse/s3_secret_key"]
+type = 'user'
+description = 'S3 secret access key for Matrix bucket'
+
+
+# Keys & stuff
+
+[secrets."chat/synapse/homeserver.signing.key"]
+type = 'user'
+description = 'Synapse homeserver ed25519 signing key'
+
+[secrets."chat/synapse/registration_shared_secret"]
+type = 'command'
+rotate = true
+command = 'head -c 32 /dev/urandom | base64'
+
+
+# ===== OLD STUFF, KEPT FOR REFERENCE ====
+
+# ----------- COTURN -----------
+
+# [secrets."chat/coturn/static-auth"]
+# type = 'user'
+# description = 'coturn static-auth (what is this?)'
+#
+# [secrets."chat/coturn/static_auth_secret_zinzdev"]
+# type = 'user'
+# description = "Serveur coturn (TURN/STUN) d'Adrien, c'est un jeton d'identification."
+
+
+# ----------- EASYBRIDGE -----------
+
+# [service_users."easybridge"]
+# description = 'Easybridge service user'
+# password_secret = 'chat/easybridge/db_pass'
+# username_secret = 'chat/easybridge/db_user'
+#
+#
+# [secrets."chat/easybridge/as_token"]
+# type = 'command'
+# rotate = true
+# command = 'openssl rand -hex 32'
+#
+# [secrets."chat/easybridge/web_session_key"]
+# type = 'command'
+# rotate = true
+# command = 'openssl rand -hex 32'
+#
+# [secrets."chat/easybridge/hs_token"]
+# type = 'command'
+# rotate = true
+# command = 'openssl rand -hex 32'
+#
diff --git a/cluster/prod/app/matrix/secrets/chat/coturn/static-auth b/cluster/prod/app/matrix/secrets/chat/coturn/static-auth
deleted file mode 100644
index 43628ef..0000000
--- a/cluster/prod/app/matrix/secrets/chat/coturn/static-auth
+++ /dev/null
@@ -1 +0,0 @@
-USER coturn static-auth (what is this?)
diff --git a/cluster/prod/app/matrix/secrets/chat/coturn/static_auth_secret_zinzdev b/cluster/prod/app/matrix/secrets/chat/coturn/static_auth_secret_zinzdev
deleted file mode 100644
index c61486d..0000000
--- a/cluster/prod/app/matrix/secrets/chat/coturn/static_auth_secret_zinzdev
+++ /dev/null
@@ -1 +0,0 @@
-USER Serveur coturn (TURN/STUN) d'Adrien, c'est un jeton d'identification. \ No newline at end of file
diff --git a/cluster/prod/app/matrix/secrets/chat/easybridge/as_token b/cluster/prod/app/matrix/secrets/chat/easybridge/as_token
deleted file mode 100644
index 5fa4e3c..0000000
--- a/cluster/prod/app/matrix/secrets/chat/easybridge/as_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 32
diff --git a/cluster/prod/app/matrix/secrets/chat/easybridge/db_pass b/cluster/prod/app/matrix/secrets/chat/easybridge/db_pass
deleted file mode 100644
index 7e1f94b..0000000
--- a/cluster/prod/app/matrix/secrets/chat/easybridge/db_pass
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_PASSWORD easybridge
diff --git a/cluster/prod/app/matrix/secrets/chat/easybridge/db_user b/cluster/prod/app/matrix/secrets/chat/easybridge/db_user
deleted file mode 100644
index 436267c..0000000
--- a/cluster/prod/app/matrix/secrets/chat/easybridge/db_user
+++ /dev/null
@@ -1 +0,0 @@
-CONST easybridge
diff --git a/cluster/prod/app/matrix/secrets/chat/easybridge/hs_token b/cluster/prod/app/matrix/secrets/chat/easybridge/hs_token
deleted file mode 100644
index 5fa4e3c..0000000
--- a/cluster/prod/app/matrix/secrets/chat/easybridge/hs_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 32
diff --git a/cluster/prod/app/matrix/secrets/chat/easybridge/web_session_key b/cluster/prod/app/matrix/secrets/chat/easybridge/web_session_key
deleted file mode 100644
index 614bed7..0000000
--- a/cluster/prod/app/matrix/secrets/chat/easybridge/web_session_key
+++ /dev/null
@@ -1,2 +0,0 @@
-CMD openssl rand -hex 32
-
diff --git a/cluster/prod/app/matrix/secrets/chat/fb2mx/as_token b/cluster/prod/app/matrix/secrets/chat/fb2mx/as_token
deleted file mode 100644
index 5fa4e3c..0000000
--- a/cluster/prod/app/matrix/secrets/chat/fb2mx/as_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 32
diff --git a/cluster/prod/app/matrix/secrets/chat/fb2mx/db_url b/cluster/prod/app/matrix/secrets/chat/fb2mx/db_url
deleted file mode 100644
index f06e265..0000000
--- a/cluster/prod/app/matrix/secrets/chat/fb2mx/db_url
+++ /dev/null
@@ -1 +0,0 @@
-USER fb2mx database URL, format: postgres://username:password@hostname/dbname
diff --git a/cluster/prod/app/matrix/secrets/chat/fb2mx/hs_token b/cluster/prod/app/matrix/secrets/chat/fb2mx/hs_token
deleted file mode 100644
index 5fa4e3c..0000000
--- a/cluster/prod/app/matrix/secrets/chat/fb2mx/hs_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 32
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.signing.key b/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.signing.key
deleted file mode 100644
index 099bd18..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.signing.key
+++ /dev/null
@@ -1 +0,0 @@
-USER Synapse homeserver ed25519 signing key
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.crt b/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.crt
deleted file mode 100644
index b696093..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.crt
+++ /dev/null
@@ -1 +0,0 @@
-SSL_CERT synapse im.deuxfleurs.fr
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.dh b/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.dh
deleted file mode 100644
index 0231fed..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.dh
+++ /dev/null
@@ -1 +0,0 @@
-USER_LONG DH parameters for matrix ssl key? how does this work?
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.key b/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.key
deleted file mode 100644
index feee544..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/homeserver.tls.key
+++ /dev/null
@@ -1 +0,0 @@
-SSL_KEY synapse im.deuxfleurs.fr
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/ldap_binddn b/cluster/prod/app/matrix/secrets/chat/synapse/ldap_binddn
deleted file mode 100644
index 2631bef..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/ldap_binddn
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_DN matrix Matrix chat server
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/ldap_bindpw b/cluster/prod/app/matrix/secrets/chat/synapse/ldap_bindpw
deleted file mode 100644
index ba07446..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/ldap_bindpw
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_PASSWORD matrix
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/postgres_db b/cluster/prod/app/matrix/secrets/chat/synapse/postgres_db
deleted file mode 100644
index 74eefa7..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/postgres_db
+++ /dev/null
@@ -1 +0,0 @@
-CONST synapse
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/postgres_pwd b/cluster/prod/app/matrix/secrets/chat/synapse/postgres_pwd
deleted file mode 100644
index ba07446..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/postgres_pwd
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_PASSWORD matrix
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/postgres_user b/cluster/prod/app/matrix/secrets/chat/synapse/postgres_user
deleted file mode 100644
index b08e86a..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/postgres_user
+++ /dev/null
@@ -1 +0,0 @@
-CONST matrix
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/registration_shared_secret b/cluster/prod/app/matrix/secrets/chat/synapse/registration_shared_secret
deleted file mode 100644
index b82f191..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/registration_shared_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD head -c 32 /dev/urandom | base64
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/s3_access_key b/cluster/prod/app/matrix/secrets/chat/synapse/s3_access_key
deleted file mode 100644
index ab09a8e..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/s3_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER matrix
diff --git a/cluster/prod/app/matrix/secrets/chat/synapse/s3_secret_key b/cluster/prod/app/matrix/secrets/chat/synapse/s3_secret_key
deleted file mode 100644
index ab09a8e..0000000
--- a/cluster/prod/app/matrix/secrets/chat/synapse/s3_secret_key
+++ /dev/null
@@ -1 +0,0 @@
-USER matrix
diff --git a/cluster/prod/app/plume/secrets.toml b/cluster/prod/app/plume/secrets.toml
new file mode 100644
index 0000000..4d68a5c
--- /dev/null
+++ b/cluster/prod/app/plume/secrets.toml
@@ -0,0 +1,10 @@
+[service_user."plume"]
+password_secret = "plume/pgsql_pw"
+
+
+[secrets."plume/secret_key"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 32'
+
+
diff --git a/cluster/prod/app/plume/secrets/plume/backup_aws_access_key_id b/cluster/prod/app/plume/secrets/plume/backup_aws_access_key_id
deleted file mode 100644
index 9235e53..0000000
--- a/cluster/prod/app/plume/secrets/plume/backup_aws_access_key_id
+++ /dev/null
@@ -1 +0,0 @@
-USER Backup AWS access key ID
diff --git a/cluster/prod/app/plume/secrets/plume/backup_aws_secret_access_key b/cluster/prod/app/plume/secrets/plume/backup_aws_secret_access_key
deleted file mode 100644
index f34677e..0000000
--- a/cluster/prod/app/plume/secrets/plume/backup_aws_secret_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Backup AWS secret access key
diff --git a/cluster/prod/app/plume/secrets/plume/backup_restic_password b/cluster/prod/app/plume/secrets/plume/backup_restic_password
deleted file mode 100644
index fbaa5fa..0000000
--- a/cluster/prod/app/plume/secrets/plume/backup_restic_password
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic password to encrypt backups
diff --git a/cluster/prod/app/plume/secrets/plume/backup_restic_repository b/cluster/prod/app/plume/secrets/plume/backup_restic_repository
deleted file mode 100644
index 3f6cb93..0000000
--- a/cluster/prod/app/plume/secrets/plume/backup_restic_repository
+++ /dev/null
@@ -1 +0,0 @@
-USER Restic repository, eg. s3:https://s3.garage.tld
diff --git a/cluster/prod/app/plume/secrets/plume/pgsql_pw b/cluster/prod/app/plume/secrets/plume/pgsql_pw
deleted file mode 100644
index 0f831bb..0000000
--- a/cluster/prod/app/plume/secrets/plume/pgsql_pw
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_PASSWORD plume
diff --git a/cluster/prod/app/plume/secrets/plume/secret_key b/cluster/prod/app/plume/secrets/plume/secret_key
deleted file mode 100644
index 978be54..0000000
--- a/cluster/prod/app/plume/secrets/plume/secret_key
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 32
diff --git a/cluster/prod/app/postgres/secrets.toml b/cluster/prod/app/postgres/secrets.toml
new file mode 100644
index 0000000..537a72d
--- /dev/null
+++ b/cluster/prod/app/postgres/secrets.toml
@@ -0,0 +1,10 @@
+[service_users."replicator"]
+password_secret = "postgres/keeper/pg_repl_pwd"
+username_secret = "postgres/keeper/pg_repl_username"
+
+
+[secrets."postgres/keeper/pg_su_pwd"]
+type = 'command'
+command = 'openssl rand -base64 15'
+description = 'postgres superuser password'
+
diff --git a/cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_pwd b/cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_pwd
deleted file mode 100644
index ae0c229..0000000
--- a/cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_pwd
+++ /dev/null
@@ -1 +0,0 @@
-SERVICE_PASSWORD replicator
diff --git a/cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_username b/cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_username
deleted file mode 100644
index 58e6e46..0000000
--- a/cluster/prod/app/postgres/secrets/postgres/keeper/pg_repl_username
+++ /dev/null
@@ -1 +0,0 @@
-CONST replicator
diff --git a/cluster/prod/app/postgres/secrets/postgres/keeper/pg_su_pwd b/cluster/prod/app/postgres/secrets/postgres/keeper/pg_su_pwd
deleted file mode 100644
index 907e2b8..0000000
--- a/cluster/prod/app/postgres/secrets/postgres/keeper/pg_su_pwd
+++ /dev/null
@@ -1 +0,0 @@
-USER postgres superuser password
diff --git a/cluster/prod/app/secretmgr b/cluster/prod/app/secretmgr
deleted file mode 120000
index 6aff4ad..0000000
--- a/cluster/prod/app/secretmgr
+++ /dev/null
@@ -1 +0,0 @@
-../../../secretmgr/secretmgr \ No newline at end of file
diff --git a/cluster/prod/app/telemetry/secrets.toml b/cluster/prod/app/telemetry/secrets.toml
new file mode 100644
index 0000000..763a14c
--- /dev/null
+++ b/cluster/prod/app/telemetry/secrets.toml
@@ -0,0 +1,16 @@
+[secrets."telemetry/grafana/admin_password"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 12'
+
+
+# S3 database storage access
+
+[secrets."telemetry/grafana/s3_access_key"]
+type = 'user'
+description = 'S3 access key for grafana db'
+
+[secrets."telemetry/grafana/s3_secret_key"]
+type = 'user'
+description = 'S3 secret key for grafana db'
+
diff --git a/cluster/prod/app/telemetry/secrets/telemetry/grafana/admin_password b/cluster/prod/app/telemetry/secrets/telemetry/grafana/admin_password
deleted file mode 100644
index 2f36e97..0000000
--- a/cluster/prod/app/telemetry/secrets/telemetry/grafana/admin_password
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 12
diff --git a/cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_access_key b/cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_access_key
deleted file mode 100644
index c7e41a4..0000000
--- a/cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 access key for grafana db
diff --git a/cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_secret_key b/cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_secret_key
deleted file mode 100644
index 051f41a..0000000
--- a/cluster/prod/app/telemetry/secrets/telemetry/grafana/s3_secret_key
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 secret key for grafana db
diff --git a/cluster/prod/secretmgr.toml b/cluster/prod/secretmgr.toml
new file mode 100644
index 0000000..ea540e5
--- /dev/null
+++ b/cluster/prod/secretmgr.toml
@@ -0,0 +1,19 @@
+[ldap]
+server = "ldap://localhost:1389"
+service_dn_suffix = "ou=services,ou=users,dc=deuxfleurs,dc=fr"
+admin_dn = "cn=admin,dc=deuxfleurs,dc=org"
+
+
+[user_values]
+"directory/ldap_base_dn" = "dc=deuxfleurs,dc=fr"
+"directory/guichet/web_hostname" = "guichet.deuxfleurs.fr"
+"directory/guichet/mail_domain" = "deuxfleurs.fr"
+"directory/guichet/s3_bucket" = "bottin-pictures"
+"directory/guichet/s3_endpoint" = "garage.deuxfleurs.fr"
+"directory/guichet/s3_region" = "garage"
+# TODO: fix smtp server, use deuxfleurs' smtp
+
+"drone-ci/s3_db_bucket" = "drone-db"
+"drone-ci/s3_storage_bucket" = "drone-storage"
+
+"chat/synapse/postgres_db" = "synapse2"
diff --git a/cluster/staging/app/convertsecrets b/cluster/staging/app/convertsecrets
new file mode 120000
index 0000000..3e30b0f
--- /dev/null
+++ b/cluster/staging/app/convertsecrets
@@ -0,0 +1 @@
+../../../secretmgr/convertsecrets \ No newline at end of file
diff --git a/cluster/staging/app/core/secrets.toml b/cluster/staging/app/core/secrets.toml
new file mode 100644
index 0000000..8da8561
--- /dev/null
+++ b/cluster/staging/app/core/secrets.toml
@@ -0,0 +1,4 @@
+[secrets."d53/gandi_api_key"]
+type = 'user'
+description = 'Gandi API key'
+
diff --git a/cluster/staging/app/core/secrets/d53/gandi_api_key b/cluster/staging/app/core/secrets/d53/gandi_api_key
deleted file mode 100644
index b3936c9..0000000
--- a/cluster/staging/app/core/secrets/d53/gandi_api_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Gandi API key
diff --git a/cluster/staging/app/directory/secrets.toml b/cluster/staging/app/directory/secrets.toml
new file mode 100644
index 0000000..edde6cc
--- /dev/null
+++ b/cluster/staging/app/directory/secrets.toml
@@ -0,0 +1,51 @@
+[secrets."directory/ldap_base_dn"]
+type = 'user'
+description = 'LDAP base DN for everything'
+example = 'dc=example,dc=com'
+
+[secrets."directory/guichet/smtp_user"]
+type = 'user'
+description = 'SMTP username'
+
+[secrets."directory/guichet/s3_access_key"]
+type = 'user'
+description = 'Garage access key for Guichet profile pictures'
+
+[secrets."directory/guichet/s3_endpoint"]
+type = 'user'
+description = 'S3 endpoint URL'
+
+[secrets."directory/guichet/s3_region"]
+type = 'user'
+description = 'S3 region'
+
+[secrets."directory/guichet/smtp_pass"]
+type = 'user'
+description = 'SMTP password'
+
+[secrets."directory/guichet/web_hostname"]
+type = 'user'
+description = 'Public hostname from which Guichet is accessible via HTTP'
+example = 'guichet.example.com'
+
+[secrets."directory/guichet/s3_bucket"]
+type = 'user'
+description = 'S3 bucket in which to store data files (such as profile pictures)'
+
+[secrets."directory/guichet/smtp_server"]
+type = 'user'
+description = 'SMTP server address (hostname:port)'
+
+[secrets."directory/guichet/s3_secret_key"]
+type = 'user'
+description = 'Garage secret key for Guichet profile pictures'
+
+[secrets."directory/guichet/mail_from"]
+type = 'user'
+description = 'E-mail address from which to send welcome emails to new users'
+
+[secrets."directory/guichet/mail_domain"]
+type = 'user'
+description = 'E-mail domain for new users'
+example = 'example.com'
+
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/mail_domain b/cluster/staging/app/directory/secrets/directory/guichet/mail_domain
deleted file mode 100644
index 5db1ba3..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/mail_domain
+++ /dev/null
@@ -1 +0,0 @@
-USER E-mail domain for new users (e.g. example.com)
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/mail_from b/cluster/staging/app/directory/secrets/directory/guichet/mail_from
deleted file mode 100644
index 9075cbf..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/mail_from
+++ /dev/null
@@ -1 +0,0 @@
-USER E-mail address from which to send welcome emails to new users
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/s3_access_key b/cluster/staging/app/directory/secrets/directory/guichet/s3_access_key
deleted file mode 100644
index e5b37ff..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/s3_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Garage access key for Guichet profile pictures
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/s3_bucket b/cluster/staging/app/directory/secrets/directory/guichet/s3_bucket
deleted file mode 100644
index cb059cf..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/s3_bucket
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 bucket in which to store data files (such as profile pictures)
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/s3_endpoint b/cluster/staging/app/directory/secrets/directory/guichet/s3_endpoint
deleted file mode 100644
index b414269..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/s3_endpoint
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 endpoint URL
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/s3_region b/cluster/staging/app/directory/secrets/directory/guichet/s3_region
deleted file mode 100644
index ef16924..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/s3_region
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 region
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/s3_secret_key b/cluster/staging/app/directory/secrets/directory/guichet/s3_secret_key
deleted file mode 100644
index f3e7f0f..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/s3_secret_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Garage secret key for Guichet profile pictures
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/smtp_pass b/cluster/staging/app/directory/secrets/directory/guichet/smtp_pass
deleted file mode 100644
index fc9d1e3..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/smtp_pass
+++ /dev/null
@@ -1 +0,0 @@
-USER SMTP password
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/smtp_server b/cluster/staging/app/directory/secrets/directory/guichet/smtp_server
deleted file mode 100644
index c453935..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/smtp_server
+++ /dev/null
@@ -1 +0,0 @@
-USER SMTP server address (hostname:port)
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/smtp_user b/cluster/staging/app/directory/secrets/directory/guichet/smtp_user
deleted file mode 100644
index c9c8bd0..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/smtp_user
+++ /dev/null
@@ -1 +0,0 @@
-USER SMTP username
diff --git a/cluster/staging/app/directory/secrets/directory/guichet/web_hostname b/cluster/staging/app/directory/secrets/directory/guichet/web_hostname
deleted file mode 100644
index afe2512..0000000
--- a/cluster/staging/app/directory/secrets/directory/guichet/web_hostname
+++ /dev/null
@@ -1 +0,0 @@
-USER Public hostname from which Guichet is accessible via HTTP (e.g. guichet.example.com)
diff --git a/cluster/staging/app/directory/secrets/directory/ldap_base_dn b/cluster/staging/app/directory/secrets/directory/ldap_base_dn
deleted file mode 100644
index ea5c7ae..0000000
--- a/cluster/staging/app/directory/secrets/directory/ldap_base_dn
+++ /dev/null
@@ -1 +0,0 @@
-USER LDAP base DN for everything (e.g. dc=example,dc=com)
diff --git a/cluster/staging/app/dummy/secrets.toml b/cluster/staging/app/dummy/secrets.toml
new file mode 100644
index 0000000..378ec46
--- /dev/null
+++ b/cluster/staging/app/dummy/secrets.toml
@@ -0,0 +1,36 @@
+[service_users."dummy"]
+description = 'Service user for dummy database access'
+username_secret = "dummy/db_username"
+password_secret = "dummy/db_password"
+rotate_password = true
+
+[secrets."dummy/s3_access_key"]
+type = 'user'
+description = 'S3 access key ID for database storage'
+
+[secrets."dummy/s3_secret_key"]
+description = 'S3 secret key for database storage'
+type = 'user'
+
+[secrets."dummy/public_domain"]
+description = 'Publicly accessible domain for dummy resource'
+type = 'user'
+
+[secrets."dummy/form_secret"]
+description = 'Form secret for dummy web pages'
+type = 'command'
+command = 'openssl rand -base64 42'
+rotate = true
+
+[secrets."dummy/signing_key"]
+description = 'Key to use to sign dummy service data'
+type = 'command'
+command = 'openssl rand -base64 42'
+
+[secrets."dummy/rpc_secret"]
+description = 'RPC secret for communication between dummy nodes'
+type = 'command'
+command = 'openssl rand -base64 42'
+rotate = true
+
+
diff --git a/cluster/staging/app/garage/secrets.toml b/cluster/staging/app/garage/secrets.toml
new file mode 100644
index 0000000..26ecd5e
--- /dev/null
+++ b/cluster/staging/app/garage/secrets.toml
@@ -0,0 +1,15 @@
+[secrets."garage-staging/admin_token"]
+type = 'command'
+rotate = true
+command = 'openssl rand -hex 32'
+
+[secrets."garage-staging/rpc_secret"]
+type = 'command'
+rotate = true
+command = 'openssl rand -hex 32'
+
+[secrets."garage-staging/metrics_token"]
+type = 'command'
+rotate = true
+command = 'openssl rand -hex 32'
+
diff --git a/cluster/staging/app/garage/secrets/garage-staging/admin_token b/cluster/staging/app/garage/secrets/garage-staging/admin_token
deleted file mode 100644
index 5fa4e3c..0000000
--- a/cluster/staging/app/garage/secrets/garage-staging/admin_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 32
diff --git a/cluster/staging/app/garage/secrets/garage-staging/metrics_token b/cluster/staging/app/garage/secrets/garage-staging/metrics_token
deleted file mode 100644
index 5fa4e3c..0000000
--- a/cluster/staging/app/garage/secrets/garage-staging/metrics_token
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 32
diff --git a/cluster/staging/app/garage/secrets/garage-staging/rpc_secret b/cluster/staging/app/garage/secrets/garage-staging/rpc_secret
deleted file mode 100644
index 5fa4e3c..0000000
--- a/cluster/staging/app/garage/secrets/garage-staging/rpc_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -hex 32
diff --git a/cluster/staging/app/im/secrets.toml b/cluster/staging/app/im/secrets.toml
new file mode 100644
index 0000000..7acad55
--- /dev/null
+++ b/cluster/staging/app/im/secrets.toml
@@ -0,0 +1,27 @@
+[secrets."synapse/s3_access_key"]
+type = 'user'
+description = 'S3 access key ID for database storage'
+
+[secrets."synapse/form_secret"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 42'
+
+[secrets."synapse/signing_key"]
+type = 'user'
+description = 'Signing key for messages'
+
+[secrets."synapse/macaroon_secret_key"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 42'
+
+[secrets."synapse/registration_shared_secret"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 42'
+
+[secrets."synapse/s3_secret_key"]
+type = 'user'
+description = 'S3 secret key for database storage'
+
diff --git a/cluster/staging/app/im/secrets/synapse/form_secret b/cluster/staging/app/im/secrets/synapse/form_secret
deleted file mode 100644
index f601137..0000000
--- a/cluster/staging/app/im/secrets/synapse/form_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 42
diff --git a/cluster/staging/app/im/secrets/synapse/macaroon_secret_key b/cluster/staging/app/im/secrets/synapse/macaroon_secret_key
deleted file mode 100644
index f601137..0000000
--- a/cluster/staging/app/im/secrets/synapse/macaroon_secret_key
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 42
diff --git a/cluster/staging/app/im/secrets/synapse/registration_shared_secret b/cluster/staging/app/im/secrets/synapse/registration_shared_secret
deleted file mode 100644
index f601137..0000000
--- a/cluster/staging/app/im/secrets/synapse/registration_shared_secret
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 42
diff --git a/cluster/staging/app/im/secrets/synapse/s3_access_key b/cluster/staging/app/im/secrets/synapse/s3_access_key
deleted file mode 100644
index 692dc34..0000000
--- a/cluster/staging/app/im/secrets/synapse/s3_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 access key ID for database storage
diff --git a/cluster/staging/app/im/secrets/synapse/s3_secret_key b/cluster/staging/app/im/secrets/synapse/s3_secret_key
deleted file mode 100644
index 8bef13c..0000000
--- a/cluster/staging/app/im/secrets/synapse/s3_secret_key
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 secret key for database storage
diff --git a/cluster/staging/app/im/secrets/synapse/signing_key b/cluster/staging/app/im/secrets/synapse/signing_key
deleted file mode 100644
index 6821360..0000000
--- a/cluster/staging/app/im/secrets/synapse/signing_key
+++ /dev/null
@@ -1 +0,0 @@
-USER Signing key for messages
diff --git a/cluster/staging/app/secretmgr b/cluster/staging/app/secretmgr
deleted file mode 120000
index 6aff4ad..0000000
--- a/cluster/staging/app/secretmgr
+++ /dev/null
@@ -1 +0,0 @@
-../../../secretmgr/secretmgr \ No newline at end of file
diff --git a/cluster/staging/app/telemetry/secrets.toml b/cluster/staging/app/telemetry/secrets.toml
new file mode 100644
index 0000000..56df97d
--- /dev/null
+++ b/cluster/staging/app/telemetry/secrets.toml
@@ -0,0 +1,13 @@
+[secrets."telemetry/grafana/s3_access_key"]
+type = 'user'
+description = 'S3 access key for grafana db'
+
+[secrets."telemetry/grafana/admin_password"]
+type = 'command'
+rotate = true
+command = 'openssl rand -base64 12'
+
+[secrets."telemetry/grafana/s3_secret_key"]
+type = 'user'
+description = 'S3 secret key for grafana db'
+
diff --git a/cluster/staging/app/telemetry/secrets/telemetry/grafana/admin_password b/cluster/staging/app/telemetry/secrets/telemetry/grafana/admin_password
deleted file mode 100644
index 2f36e97..0000000
--- a/cluster/staging/app/telemetry/secrets/telemetry/grafana/admin_password
+++ /dev/null
@@ -1 +0,0 @@
-CMD openssl rand -base64 12
diff --git a/cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_access_key b/cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_access_key
deleted file mode 100644
index c7e41a4..0000000
--- a/cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_access_key
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 access key for grafana db
diff --git a/cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_secret_key b/cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_secret_key
deleted file mode 100644
index 051f41a..0000000
--- a/cluster/staging/app/telemetry/secrets/telemetry/grafana/s3_secret_key
+++ /dev/null
@@ -1 +0,0 @@
-USER S3 secret key for grafana db
diff --git a/cluster/staging/secretmgr.toml b/cluster/staging/secretmgr.toml
new file mode 100644
index 0000000..9dc0aa5
--- /dev/null
+++ b/cluster/staging/secretmgr.toml
@@ -0,0 +1,19 @@
+[ldap]
+server = "ldap://localhost:1389"
+service_dn_suffix = "ou=services,ou=users,dc=staging,dc=deuxfleurs,dc=org"
+admin_dn = "cn=admin,dc=staging,dc=deuxfleurs,dc=org"
+admin_password_secret = "directory/admin_password"
+
+[user_values]
+"directory/ldap_base_dn" = "dc=staging,dc=deuxfleurs,dc=org"
+"directory/guichet/mail_domain" = "staging.deuxfleurs.org"
+"directory/guichet/mail_from" = "contact@deuxfleurs.org"
+"directory/guichet/s3_bucket" = "bottin-pictures"
+"directory/guichet/s3_endpoint" = "garage.staging.deuxfleurs.org"
+"directory/guichet/s3_region" = "garage-staging"
+"directory/guichet/smtp_server" = "mail.gandi.net:25"
+"directory/guichet/smtp_user" = "contact@deuxfleurs.org"
+"directory/guichet/web_hostname" = "guichet.staging.deuxfleurs.org"
+
+"dummy/public_domain" = "dummy.staging.deuxfleurs.org"
+"dummy/test_constant" = "test value"
diff --git a/secretmgr b/secretmgr
new file mode 100755
index 0000000..1507008
--- /dev/null
+++ b/secretmgr
@@ -0,0 +1,576 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.pip ps.consul ps.ldap ps.passlib ps.requests ps.six ps.toml ])"
+
+# DEPENDENCY: python-consul
+import consul
+
+# DEPENDENCY: python-ldap
+import ldap
+
+# DEPENDENCY: passlib
+from passlib.hash import ldap_salted_sha1
+
+# DEPENDENCY: toml
+import toml
+
+import os
+import sys
+import glob
+import subprocess
+import getpass
+import base64
+from secrets import token_bytes
+
+"""
+This is a utility to handle secrets in the Consul database
+for the various components of the Deuxfleurs infrastructure
+
+Functionnalities:
+- check that secrets are correctly configured
+- help user fill in secrets
+- create LDAP service users and fill in corresponding secrets
+- TODO: manage Garage buckets and access keys
+- maybe one day: manage SSL certificates and keys
+"""
+
+# ---- UTIL ----
+
+consul_server = consul.Consul()
+
+class bcolors:
+ HEADER = '\033[95m'
+ OKBLUE = '\033[94m'
+ OKCYAN = '\033[96m'
+ OKGREEN = '\033[92m'
+ WARNING = '\033[93m'
+ FAIL = '\033[91m'
+ ENDC = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+
+
+# ---- SECRETS ----
+
+class Secret:
+ def __init__(self, key, config, description=None):
+ self.config = config
+ self.key = key
+ if description != None:
+ self.description = description
+ else:
+ self.description = None
+
+ def check(self, value):
+ return True
+
+ def generate(self):
+ pass
+
+ def rotate(self):
+ return None
+
+ def print_info(self):
+ print("Secret: {}".format(self.key))
+ print("Type: {}".format(self.__class__.TYPE))
+ if self.description != None:
+ print("Description: {}".format(self.description))
+
+class UserSecret(Secret):
+ TYPE = "user-entered secret"
+
+ def __init__(self, example=None, multiline=False, **kwargs):
+ Secret.__init__(self, **kwargs)
+ self.example = example
+ self.multiline = multiline
+
+ def print_info(self):
+ Secret.print_info(self)
+ if self.key in self.config.user_values:
+ print("Cluster value: {}".format(self.config.user_values[self.key]))
+ elif self.example != None:
+ print("Example: {}".format(self.example))
+
+ def generate(self):
+ if self.key in self.config.user_values:
+ print("Using constant value from cluster's secretmgr.toml")
+ return self.config.user_values[self.key]
+
+ print("Enter value for secret, or ^C to skip:")
+ if self.multiline:
+ print("THIS IS A LONG VALUE, ENTER SEVERAL LINES AND FINISH WITH A LINE CONTAINING A SINGLE .")
+ try:
+ lines = []
+ while True:
+ line = input().strip()
+ if line == ".":
+ break
+ lines.append(line)
+ return "\n".join(lines)
+ except KeyboardInterrupt:
+ return None
+ else:
+ try:
+ while True:
+ line = input().strip()
+ if line != "":
+ return line
+ else:
+ print("Please enter a non-empty value, or ^C to skip:")
+ except KeyboardInterrupt:
+ return None
+
+class CommandSecret(Secret):
+ TYPE = "command"
+
+ def __init__(self, command, rotate=False, **kwargs):
+ Secret.__init__(self, **kwargs)
+ self.command = command
+ self.rotate_value = rotate
+
+ def print_info(self):
+ Secret.print_info(self)
+ print("Command: {}".format(self.command))
+ if self.rotate_value:
+ print("Rotate: True")
+
+ def generate(self):
+ print("Executing command:", self.command)
+ return subprocess.check_output(["sh", "-c", self.command])
+
+ def rotate(self):
+ if self.rotate_value:
+ return self.generate()
+ else:
+ return None
+
+class ConstantSecret(Secret):
+ TYPE = "constant value"
+
+ def __init__(self, value, **kwargs):
+ Secret.__init__(self, **kwargs)
+ self.value = value
+
+ def print_info(self):
+ Secret.print_info(self)
+ print("Value: {}".format(self.value))
+
+ def check(self, value):
+ return value == self.value
+
+ def generate(self):
+ return self.value
+
+
+# ---- SERVICE USERS ----
+
+class ServiceUserPasswordSecret(Secret):
+ TYPE = "service user's password"
+
+ def __init__(self, service_user, **kwargs):
+ Secret.__init__(self, **kwargs)
+ self.service_user = service_user
+
+ def print_info(self):
+ Secret.print_info(self)
+ print("Service user: {}".format(self.service_user.username))
+
+ def check(self, value):
+ l = ldap.initialize(self.config.ldap_server)
+ try:
+ l.simple_bind_s(self.service_user.dn, value)
+ return True
+ except Exception as e:
+ return False
+
+ def generate(self):
+ return self.service_user.password
+
+ def rotate(self):
+ return self.service_user.password
+
+class ServiceUserNameSecret(Secret):
+ TYPE = "service user's username (constant value)"
+
+ def __init__(self, service_user, **kwargs):
+ Secret.__init__(self, **kwargs)
+ self.service_user = service_user
+
+ def print_info(self):
+ Secret.print_info(self)
+ print("Value: {}".format(self.service_user.username))
+
+ def check(self, value):
+ return value == self.service_user.username
+
+ def generate(self):
+ return self.service_user.username
+
+class ServiceUserDNSecret(Secret):
+ TYPE = "service user's DN (constant value)"
+
+ def __init__(self, service_user, **kwargs):
+ Secret.__init__(self, **kwargs)
+ self.service_user = service_user
+
+ def print_info(self):
+ Secret.print_info(self)
+ print("Service user: {}".format(self.service_user.username))
+ print("Value: {}".format(self.service_user.dn))
+
+ def check(self, value):
+ return value == self.service_user.dn
+
+ def generate(self):
+ return self.service_user.dn
+
+class ServiceUser:
+ def __init__(self, username, password_secret, config, description=None, dn_secret=None, username_secret=None, rotate_password=False):
+ self.config = config
+ self.username = username
+ self.description = description
+ self.password = None
+ self.dn = "cn={},{}".format(self.username, self.config.ldap_service_dn_suffix)
+ self.rotate_password = rotate_password
+
+ self.password_secret = ServiceUserPasswordSecret(config=config, service_user=self, key=password_secret)
+
+ self.username_secret = None
+ if username_secret != None:
+ self.username_secret = ServiceUserNameSecret(config=config, service_user=self, key=username_secret)
+
+ self.dn_secret = None
+ if dn_secret != None:
+ self.dn_secret = ServiceUserDNSecret(config=config, service_user=self, key=dn_secret)
+
+ def secrets(self):
+ secrets = {}
+ secrets[self.password_secret.key] = self.password_secret
+ if self.dn_secret != None:
+ secrets[self.dn_secret.key] = self.dn_secret
+ if self.username_secret != None:
+ secrets[self.username_secret.key] = self.username_secret
+ return secrets
+
+ def configure(self, rotate):
+ self.password = self.config.get_secret(self.password_secret.key)
+ if self.password is None:
+ good = False
+ else:
+ l = ldap.initialize(self.config.ldap_server)
+ try:
+ l.simple_bind_s(self.dn, self.password)
+ good = True
+ except:
+ good = False
+
+ if not good or (rotate and self.rotate_password):
+ # Reset passsword
+ self.password = base64.urlsafe_b64encode(token_bytes(12)).decode('ascii')
+ pass_crypt = ldap_salted_sha1.hash(self.password).encode('ascii')
+
+ l = self.config.get_ldap_admin_conn()
+ res = l.search_s(self.dn, ldap.SCOPE_BASE, "objectclass=*")
+ if res is None or len(res) == 0:
+ print(bcolors.OKCYAN, "Creating entity", self.dn, bcolors.ENDC)
+ if self.config.dry_run:
+ print(bcolors.OKBLUE, "Dry run, skipping. Add --do to actually do something.", bcolors.ENDC)
+ return
+ l.add_s(self.dn,
+ [
+ ("objectclass", [b"person", b"top"]),
+ ("displayname", [self.description.encode('ascii')]),
+ ("userpassword", [pass_crypt]),
+ ])
+ else:
+ print(bcolors.OKCYAN, "Resetting password for entity", self.dn, bcolors.ENDC)
+ if self.config.dry_run:
+ print(bcolors.OKBLUE, "Dry run, skipping. Add --do to actually do something.", bcolors.ENDC)
+ return
+ l.modify_s(self.dn,
+ [
+ (ldap.MOD_REPLACE, "userpassword", [pass_crypt])
+ ])
+ else:
+ print(bcolors.OKGREEN, "Entity is good: ", self.dn, bcolors.ENDC)
+
+
+# ---- MAIN CONFIG CLASS ----
+
+class Config:
+ def __init__(self, cluster_name, dry_run):
+ self.cluster_name = cluster_name
+ self.app_path = os.path.join(".", "cluster", cluster_name, "app")
+
+ self.service_users = {}
+ self.secrets = {}
+ self.modules = []
+ self.dry_run = dry_run
+
+ # Load config from secretmgr.toml in cluster directory
+ secretmgr_toml_path = os.path.join(".", "cluster", cluster_name, "secretmgr.toml")
+ if os.path.exists(secretmgr_toml_path):
+ with open(secretmgr_toml_path) as f:
+ secretmgr_toml = toml.load(f)
+ else:
+ secretmgr_toml = {}
+
+ if "user_values" in secretmgr_toml:
+ self.user_values = secretmgr_toml["user_values"]
+ else:
+ self.user_values = {}
+
+ self.ldap_server = None
+ self.ldap_service_dn_suffix = None
+ self.ldap_admin_dn = None
+ self.ldap_admin_password_secret = None
+ self.ldap_admin_conn = None
+ if "ldap" in secretmgr_toml:
+ if "server" in secretmgr_toml["ldap"]:
+ self.ldap_server = secretmgr_toml["ldap"]["server"]
+ if "service_dn_suffix" in secretmgr_toml["ldap"]:
+ self.ldap_service_dn_suffix = secretmgr_toml["ldap"]["service_dn_suffix"]
+ if "admin_dn" in secretmgr_toml["ldap"]:
+ self.ldap_admin_dn = secretmgr_toml["ldap"]["admin_dn"]
+ if "admin_password_secret" in secretmgr_toml["ldap"]:
+ self.ldap_admin_password_secret = secretmgr_toml["ldap"]["admin_password_secret"]
+
+ def load_module(self, module_name):
+ secrets_toml_path = os.path.join(self.app_path, module_name, "secrets.toml")
+
+ with open(secrets_toml_path) as f:
+ secrets_toml = toml.load(f)
+
+ self.modules.append(module_name)
+
+ # Service users, and their associated secrets
+ if "service_users" in secrets_toml:
+ for (uname, uargs) in secrets_toml["service_users"].items():
+ service_user = ServiceUser(uname, config=self, **uargs)
+ for (skey, secret) in service_user.secrets().items():
+ if skey in self.secrets:
+ raise Exception("Duplicate secret: {}".format(skey))
+ self.secrets[skey] = secret
+ self.service_users[uname] = service_user
+
+ # Other secrets
+ if "secrets" in secrets_toml:
+ for (skey, sargs) in secrets_toml["secrets"].items():
+ ty = sargs["type"]
+ del sargs["type"]
+ if ty == "user":
+ secret = UserSecret(config=self, key=skey, **sargs)
+ elif ty == "command":
+ secret = CommandSecret(config=self, key=skey, **sargs)
+ elif ty == "constant":
+ secret = ConstantSecret(config=self, key=skey, **sargs)
+ elif ty == "service_password":
+ service = sargs["service"]
+ del sargs["service"]
+ secret = ServiceUserPasswordSecret(
+ config=self,
+ key=skey,
+ service_user=self.service_users[service],
+ **sargs)
+ elif ty == "service_username":
+ service = sargs["service"]
+ del sargs["service"]
+ secret = ServiceUserNameSecret(
+ config=self,
+ key=skey,
+ service_user=self.service_users[service],
+ **sargs)
+ elif ty == "service_dn":
+ service = sargs["service"]
+ del sargs["service"]
+ secret = ServiceUserDNSecret(
+ config=self,
+ key=skey,
+ service_user=self.service_users[service],
+ **sargs)
+ else:
+ description = "{}, {}".format(ty,
+ ", ".join([k + ": " + v for k, v in sargs.items()]))
+ secret = UserSecret(
+ config=self,
+ key=skey,
+ multiline=True,
+ description=description)
+ if skey in self.secrets:
+ raise Exception("Duplicate secret: {}".format(skey))
+ self.secrets[skey] = secret
+
+ def add_user_values_secrets(self):
+ for (skey, value) in self.user_values.items():
+ self.secrets[skey] = ConstantSecret(
+ config=self,
+ key=skey,
+ value=value,
+ description="Cluster-defined user value")
+
+ # -- consul and ldap helpers --
+
+ def check_consul_cluster(self):
+ # Check cluster name we are connected to
+ consul_node = consul_server.agent.self()
+ if consul_node["Config"]["Datacenter"] != self.cluster_name:
+ print("You are not connected to the correct Consul cluster.")
+ print("You are connected to cluster '{}' instead of '{}'.".format(consul_node["Config"]["Datacenter"], self.cluster_name))
+ sys.exit(1)
+
+ def get_ldap_admin_conn(self):
+ if self.ldap_admin_conn is None:
+ if self.ldap_admin_password_secret != None:
+ ldap_pass = self.get_secret(self.ldap_admin_password_secret)
+ if ldap_pass is None:
+ raise Exception("LDAP admin password could not be read at: {}".format(pass_key))
+ else:
+ ldap_pass = getpass.getpass("LDAP admin password: ")
+
+ self.ldap_admin_conn = ldap.initialize(self.ldap_server)
+ self.ldap_admin_conn.simple_bind_s(self.ldap_admin_dn, ldap_pass)
+ return self.ldap_admin_conn
+
+ def get_secret(self, key):
+ _, data = consul_server.kv.get("secrets/" + key)
+ if data is None:
+ return None
+ else:
+ return data["Value"].decode('ascii').strip()
+
+ def put_secret(self, key, value):
+ if self.dry_run:
+ print(bcolors.OKBLUE, "Dry run, not updating secrets/{}. Add --do to actually do something.".format(key), bcolors.ENDC)
+ return
+ consul_server.kv.put("secrets/" + key, value)
+
+ # -- user actions --
+
+ def print_info(self):
+ print("== LIST OF SERVICE USERS ==")
+ print()
+ for (_, su) in self.service_users.items():
+ print("Username: {}".format(su.username))
+ print("DN: {}".format(su.dn))
+ print("Pass. secret: {}".format(su.password_secret.key))
+ print()
+
+ print("== LIST OF SECRETS ==")
+ print()
+ for (_, secret) in self.secrets.items():
+ secret.print_info()
+ print()
+
+ def check_secrets(self):
+ self.check_consul_cluster()
+ print(":: Checking secrets...")
+ must_gen = False
+ for (_, secret) in self.secrets.items():
+ value = self.get_secret(secret.key)
+ if value is None:
+ print(secret.key, bcolors.FAIL, "x missing", bcolors.ENDC)
+ must_gen = True
+ elif not secret.check(value):
+ print(secret.key, bcolors.WARNING, "x bad value", bcolors.ENDC)
+ must_gen = True
+ else:
+ print(secret.key, bcolors.OKGREEN, "✓", bcolors.ENDC)
+ print()
+ if must_gen:
+ print("To fix missing or invalid secrets, use `secretmgr gen <cluster_name> <app>...`")
+ print()
+
+ def gen_secrets(self):
+ self.check_consul_cluster()
+ if len(self.service_users) > 0:
+ print(":: Configuring service users...")
+ for (_, su) in self.service_users.items():
+ su.configure(False)
+ print()
+
+ print(":: Generating missing/invalid secrets...")
+ for (_, secret) in self.secrets.items():
+ old_value = self.get_secret(secret.key)
+ if old_value is None or not secret.check(old_value):
+ print()
+ secret.print_info()
+ value = secret.generate()
+ if value != None:
+ self.put_secret(secret.key, value)
+ print(bcolors.OKCYAN, "Value set.", bcolors.ENDC)
+ else:
+ print(bcolors.WARNING, "Skipped.", bcolors.ENDC)
+
+ print()
+ self.check_secrets()
+
+ def rotate_secrets(self):
+ self.check_consul_cluster()
+ if len(self.service_users) > 0:
+ print(":: Regenerating service user passwords...")
+ for (_, su) in self.service_users.items():
+ su.configure(True)
+ print()
+
+ print(":: Rotating secrets...")
+ for (_, secret) in self.secrets.items():
+ print()
+ secret.print_info()
+
+ old_value = self.get_secret(secret.key)
+ new_value = secret.rotate()
+
+ if new_value != None and new_value != old_value:
+ self.put_secret(secret.key, new_value)
+ print(bcolors.OKCYAN, "Value set.", bcolors.ENDC)
+ else:
+ print(bcolors.OKGREEN, "Nothing to do.", bcolors.ENDC)
+
+ print()
+ self.check_secrets()
+
+
+# ---- MAIN ----
+
+def load_config(cluster_name, modules, **kwargs):
+ # Load config
+ cfg = Config(cluster_name, **kwargs)
+ if len(modules) > 0:
+ for mod in modules:
+ cfg.load_module(mod)
+ else:
+ cfg.add_user_values_secrets()
+
+ return cfg
+
+if __name__ == "__main__":
+ verb = None
+ dry_run = True
+
+ for i, val in enumerate(sys.argv):
+ if val == "--do":
+ dry_run = False
+ elif val == "info":
+ verb = lambda cfg: cfg.print_info()
+ break
+ elif val == "check":
+ verb = lambda cfg: cfg.check_secrets()
+ break
+ elif val == "gen":
+ verb = lambda cfg: cfg.gen_secrets()
+ break
+ elif val == "rotate":
+ verb = lambda cfg: cfg.rotate_secrets()
+ break
+
+ if verb is None:
+ print("Usage:")
+ print(" secretmgr [--do] info|check|gen|rotate <cluster name> [<module name>...]")
+ else:
+ cfg = load_config(
+ cluster_name=sys.argv[i+1],
+ modules=sys.argv[i+2:],
+ dry_run=dry_run)
+ verb(cfg)
+
+
+# vim: set sts=4 ts=4 sw=4 tw=0 ft=python et :
diff --git a/secretmgr/secretmgr b/secretmgr/secretmgr
deleted file mode 100755
index 0595f81..0000000
--- a/secretmgr/secretmgr
+++ /dev/null
@@ -1,382 +0,0 @@
-#!/usr/bin/env nix-shell
-#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.pip ps.consul ps.ldap ps.passlib ps.requests ps.six ])"
-
-# DEPENDENCY: python-consul
-import consul
-
-# DEPENDENCY: python-ldap
-import ldap
-
-# DEPENDENCY: passlib
-from passlib.hash import ldap_salted_sha1
-
-import os
-import sys
-import glob
-import subprocess
-import getpass
-import base64
-from secrets import token_bytes
-
-
-"""
-TODO: this will be a utility to handle secrets in the Consul database
-for the various components of the Deuxfleurs infrastructure
-
-Functionnalities:
-- check that secrets are correctly configured
-- help user fill in secrets
-- create LDAP service users and fill in corresponding secrets
-- maybe one day: manage SSL certificates and keys
-
-It uses files placed in <module_name>/secrets/* to know what secrets
-it should handle. These secret files contain directives for what to do
-about these secrets.
-
-Example directives:
-
-USER <description>
-(a secret that must be filled in by the user)
-
-USER_LONG <description>
-(the same, indicates that the secret fits on several lines)
-
-CMD <command>
-(a secret that is generated by running this command)
-
-CMD_ONCE <command>
-(same, but value is not changed when doing a regen)
-
-CONST <constant value>
-(the secret has a constant value set here)
-
-CONST_LONG
-<constant value, several lines>
-(same)
-
-SERVICE_DN <service name> <service description>
-(the LDAP DN of a service user)
-
-SERVICE_PASSWORD <service name>
-(the LDAP password for the corresponding service user)
-
-SSL_CERT <cert name> <list of domains>
-(a SSL domain for the given domains)
-
-SSL_KEY <cert name>
-(the SSL key going with corresponding certificate)
-
-RSA_PUBLIC_KEY <key name> <key description>
-(a public RSA key)
-
-RSA_PRIVATE_KEY <key name>
-(the corresponding private RSA key)
-"""
-
-
-# Parameters
-LDAP_URL = "ldap://localhost:1389"
-SERVICE_DN_SUFFIX = "ou=services,ou=users,dc=deuxfleurs,dc=fr"
-consul_server = consul.Consul()
-
-
-# ----
-
-USER = "USER"
-USER_LONG = "USER_LONG"
-CMD = "CMD"
-CMD_ONCE = "CMD_ONCE"
-CONST = "CONST"
-CONST_LONG = "CONST_LONG"
-SERVICE_DN = "SERVICE_DN"
-SERVICE_PASSWORD = "SERVICE_PASSWORD"
-SSL_CERT = "SSL_CERT"
-SSL_KEY = "SSL_KEY"
-RSA_PUBLIC_KEY = "RSA_PUBLIC_KEY"
-RSA_PRIVATE_KEY = "RSA_PRIVATE_KEY"
-
-class bcolors:
- HEADER = '\033[95m'
- OKBLUE = '\033[94m'
- OKCYAN = '\033[96m'
- OKGREEN = '\033[92m'
- WARNING = '\033[93m'
- FAIL = '\033[91m'
- ENDC = '\033[0m'
- BOLD = '\033[1m'
- UNDERLINE = '\033[4m'
-
-def read_secret(key, file_path):
- lines = [l.strip() for l in open(file_path, "r")]
- if len(lines) == 0:
- print(bcolors.FAIL, "ERROR:", bcolors.ENDC, "Empty file in", file_path)
- sys.exit(-1)
- l0 = lines[0].split(" ")
- stype = l0[0]
- secret = {"type": stype, "key": key}
- if stype in [USER, USER_LONG]:
- secret["desc"] = " ".join(l0[1:])
- elif stype in [CMD, CMD_ONCE]:
- secret["cmd"] = " ".join(l0[1:])
- elif stype == CONST:
- secret["value"] = " ".join(l0[1:])
- elif stype == CONST_LONG:
- secret["value"] = "\n".join(lines[1:])
- elif stype in [SERVICE_DN, SERVICE_PASSWORD]:
- secret["service"] = l0[1]
- if stype == SERVICE_DN:
- secret["service_desc"] = " ".join(l0[2:])
- elif stype in [SSL_CERT, SSL_KEY]:
- secret["cert_name"] = l0[1]
- if stype == SSL_CERT:
- secret["cert_domains"] = l0[2:]
- elif stype in [RSA_PUBLIC_KEY, RSA_PRIVATE_KEY]:
- secret["key_name"] = l0[1]
- if stype == RSA_PUBLIC_KEY:
- secret["key_desc"] = " ".join(l0[2:])
- else:
- print(bcolors.FAIL, "ERROR:", bcolors.ENDC, "Invalid secret type", stype, "in", file_path)
- sys.exit(-1)
-
- return secret
-
-def read_secrets(module_list):
- secrets = {}
- for mod in module_list:
- for file_path in glob.glob(mod.strip('/') + "/secrets/**", recursive=True):
- if os.path.isfile(file_path):
- key = '/'.join(file_path.split("/")[1:])
- secrets[key] = read_secret(key, file_path)
- return secrets
-
-def get_secrets_services(secrets):
- services = {}
- for key, secret in secrets.items():
- if secret["type"] not in [SERVICE_DN, SERVICE_PASSWORD]:
- continue
- svc = secret["service"]
- print(svc, "@", key, bcolors.OKCYAN, "...", bcolors.ENDC)
- if svc not in services:
- services[svc] = {
- "dn": "cn=%s,%s"%(svc, SERVICE_DN_SUFFIX),
- "desc": "(not provided)",
- "pass": None,
- "dn_at": [],
- "pass_at": [],
- }
- if secret["type"] == SERVICE_DN:
- services[svc]["dn_at"].append(key)
- services[svc]["desc"] = secret["service_desc"]
-
- if secret["type"] == SERVICE_PASSWORD:
- services[svc]["pass_at"].append(key)
- _, data = consul_server.kv.get(key)
- if data is not None:
- if services[svc]["pass"] is None:
- services[svc]["pass"] = data["Value"].decode('ascii').strip()
-
- return services
-
-ldap_admin_conn = None
-def get_ldap_admin_conn():
- global ldap_admin_conn
- if ldap_admin_conn is None:
- ldap_admin_conn = ldap.initialize(LDAP_URL)
- ldap_user = input("LDAP admin user (full DN, please!): ")
- ldap_pass = getpass.getpass("LDAP admin password: ")
- ldap_admin_conn.simple_bind_s(ldap_user, ldap_pass)
- return ldap_admin_conn
-
-# ---- CHECK COMMAND ----
-
-def check_secrets(module_list):
- secrets = read_secrets(module_list)
- print("Found", len(secrets), "secrets to check")
- print()
-
- check_secrets_presence(secrets)
- check_secrets_services(secrets)
-
-def check_secrets_presence(secrets):
- print("Checking secrets presence...")
- for key in secrets.keys():
- _, data = consul_server.kv.get(key)
- if data is None:
- print(key, bcolors.FAIL, "x", bcolors.ENDC)
- else:
- print(key, bcolors.OKGREEN, "✓", bcolors.ENDC)
- print()
-
-def check_secrets_services(secrets):
- print("Checking secrets for LDAP service users...")
- services = get_secrets_services(secrets)
-
- for svc_name, svc in services.items():
- for dn_key in svc["dn_at"]:
- _, data = consul_server.kv.get(dn_key)
- if data is not None:
- got_val = data["Value"].decode('ascii').strip()
- if got_val != svc["dn"]:
- print(svc_name, "wrong DN at", dn_key, bcolors.FAIL, "x", bcolors.ENDC)
- print("got:", got_val, "instead of:", svc["dn"])
-
- if svc["pass"] is None:
- print(svc_name, bcolors.FAIL, "no password stored", bcolors.ENDC)
- else:
- for pass_key in svc["pass_at"]:
- _, data = consul_server.kv.get(pass_key)
- if data is not None:
- got_val = data["Value"].decode('ascii').strip()
- if got_val != svc["pass"]:
- print(svc_name, "wrong pass at", dn_key, bcolors.FAIL, "x", bcolors.ENDC)
-
- l = ldap.initialize(LDAP_URL)
- try:
- l.simple_bind_s(svc["dn"], svc["pass"])
- print(svc_name, bcolors.OKGREEN, "✓", bcolors.ENDC)
- except Exception as e:
- print(svc_name, bcolors.FAIL, e, bcolors.ENDC)
- print()
-
-
-# ---- GEN COMMAND ----
-
-def gen_secrets(module_list, regen):
- secrets = read_secrets(module_list)
- print("Found", len(secrets), "secrets to check and maybe generate")
- print()
-
- gen_secrets_base(secrets, regen)
- gen_secrets_services(secrets, regen)
-
- check_secrets_presence(secrets)
- check_secrets_services(secrets)
-
-def gen_secrets_base(secrets, regen):
- print("Filling in user secrets and cmd secrets...")
-
- for key, secret in secrets.items():
- _, data = consul_server.kv.get(key)
- if data is not None and not regen:
- continue
-
- if secret["type"] == USER:
- print("----")
- print(key)
- print("Description:", secret["desc"])
- print("Enter value for secret, or ^C to skip:")
- try:
- val = input().strip()
- consul_server.kv.put(key, val)
- print(bcolors.OKCYAN, "Value set.", bcolors.ENDC)
- except KeyboardInterrupt:
- print(bcolors.WARNING, "Skipped.", bcolors.ENDC)
-
- if secret["type"] == USER_LONG:
- print("----")
- print(key)
- print("Description:", secret["desc"])
- print("Enter value for secret, or ^C to skip:")
- print("THIS IS A LONG VALUE, ENTER SEVERAL LINES AND FINISH WITH A LINE CONTAINING A SINGLE .")
- try:
- lines = []
- while True:
- line = input().strip()
- if line == ".":
- break
- lines.append(line)
- val = "\n".join(lines)
- consul_server.kv.put(key, val)
- print(bcolors.OKCYAN, "Value set.", bcolors.ENDC)
- except KeyboardInterrupt:
- print(bcolors.WARNING, "Skipped.", bcolors.ENDC)
-
- if secret["type"] in [CONST, CONST_LONG]:
- print("----")
- print(key)
- print("Resetting to constant value.")
- consul_server.kv.put(key, secret["value"])
- print(bcolors.OKCYAN, "Value set.", bcolors.ENDC)
-
- if secret["type"] == CMD or (secret["type"] == CMD_ONCE and data is None):
- print("----")
- print(key)
- print("Executing command:", secret["cmd"])
- val = subprocess.check_output(["sh", "-c", secret["cmd"]])
- consul_server.kv.put(key, val)
- print(bcolors.OKCYAN, "Value set.", bcolors.ENDC)
-
- print()
-
-def gen_secrets_services(secrets, regen):
- print("Generating LDAP service accounts...")
- services = get_secrets_services(secrets)
-
- for svc_name, svc in services.items():
- print("----")
- print("Service:", svc_name)
- print("Description:", svc["desc"])
-
- for dn_key in svc["dn_at"]:
- _, data = consul_server.kv.get(dn_key)
- if data is None or data["Value"].decode('ascii').strip() != svc["dn"]:
- print(bcolors.OKCYAN, "Setting DN", bcolors.ENDC, "at", dn_key)
- consul_server.kv.put(dn_key, svc["dn"])
-
- if svc["pass"] is None or regen:
- print(bcolors.OKCYAN, "Generating new password", bcolors.ENDC)
- svc["pass"] = base64.urlsafe_b64encode(token_bytes(12)).decode('ascii')
-
- l = ldap.initialize(LDAP_URL)
- try:
- l.simple_bind_s(svc["dn"], svc["pass"])
- except:
- fix_service_user(svc)
-
- for pass_key in svc["pass_at"]:
- _, data = consul_server.kv.get(pass_key)
- if data is None or data["Value"].decode('ascii').strip() != svc["pass"]:
- print(bcolors.OKCYAN, "Setting password", bcolors.ENDC, "at", pass_key)
- consul_server.kv.put(pass_key, svc["pass"])
-
- print()
-
-def fix_service_user(svc):
- print("Fixing service user", svc["dn"], "...")
- l = get_ldap_admin_conn()
- res = l.search_s(svc["dn"], ldap.SCOPE_BASE, "objectclass=*")
- pass_crypt = ldap_salted_sha1.hash(svc["pass"])
- if res is None or len(res) == 0:
- print(bcolors.OKCYAN, "Creating entity...", bcolors.ENDC)
- l.add_s(svc["dn"],
- [
- ("objectclass", [b"person", b"top"]),
- ("displayname", [svc["desc"].encode('ascii')]),
- ("userpassword", [pass_crypt.encode('ascii')]),
- ])
- else:
- print(bcolors.OKCYAN, "Resetting entity password", bcolors.ENDC)
- l.modify_s(svc["dn"],
- [
- (ldap.MOD_REPLACE, "userpassword", [pass_crypt.encode('ascii')])
- ])
-
-# ---- MAIN ----
-
-if __name__ == "__main__":
- for i, val in enumerate(sys.argv):
- if val == "check":
- check_secrets(sys.argv[i+1:])
- break
- elif val == "gen":
- gen_secrets(sys.argv[i+1:], False)
- break
- elif val == "regen":
- gen_secrets(sys.argv[i+1:], True)
- break
- else:
- print("Usage:")
- print(" secretmgr.py [check|gen|regen] <module name>...")
-
-
-# vim: set sts=4 ts=4 sw=4 tw=0 ft=python et :