From 92d7861e895fb79086d04c79cf9a6646fd839d66 Mon Sep 17 00:00:00 2001 From: YuviPanda Date: Fri, 9 Sep 2022 22:20:22 -0700 Subject: [PATCH] Add docs on decrypting encrypted messages as a team Should have an equivalent PR to the docs repo targetted towards the people who are *sending* us stuff. Ref https://github.com/2i2c-org/infrastructure/issues/639 --- .sops.yaml | 2 ++ docs/howto/support/decrypt-age.md | 42 ++++++++++++++++++++++ docs/howto/support/index.md | 11 ++++++ docs/index.md | 1 + docs/reference/tools.md | 2 ++ shared/keys/decrypt-age.py | 59 +++++++++++++++++++++++++++++++ shared/keys/enc-age-private.key | 21 +++++++++++ 7 files changed, 138 insertions(+) create mode 100644 docs/howto/support/decrypt-age.md create mode 100644 docs/howto/support/index.md create mode 100755 shared/keys/decrypt-age.py create mode 100644 shared/keys/enc-age-private.key diff --git a/.sops.yaml b/.sops.yaml index cbccdb7bb1..00fb04b6a9 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -3,3 +3,5 @@ creation_rules: gcp_kms: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs - path_regex: .*/eksctl/ssh-keys/.* gcp_kms: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs + - path_regex: shared/keys/.*key.* + gcp_kms: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs diff --git a/docs/howto/support/decrypt-age.md b/docs/howto/support/decrypt-age.md new file mode 100644 index 0000000000..d08e859db9 --- /dev/null +++ b/docs/howto/support/decrypt-age.md @@ -0,0 +1,42 @@ +# Decrypt encrypted information sent to `support@2i2c.org` + +Sometimes community representatives need to send us *encrypted* information - +usually credentials for cloud access or an authentication system. We use +[age](https://age-encryption.org/) (pronounced *aghe*) to allow such information to +be encrypted and then sent to use in a way that *anyone* on the team can decrypt, +rather than the information be tied to a single engineer. + +## Pre-requisites + +Before you can decrypt received messages, you need the following pre-requisites setup. + +1. [Install age](https://github.com/FiloSottile/age#installation) +2. [Install sops](tools:sops) +3. [Authenticate with gcloud](tools:gcloud:auth) so sops can decrypt the private age + key kept in the repository. + +These are all one-time tasks, and (2) and (3) are generally required for deployments to work. + +## Decrypt received message + +The encrypted message looks something like + +``` +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5cDRlMzVzWHpWU1JIeVBj +YnBqOHc5NzA3ZTZiNlljSkRDMFpyMkNUWVhBCmRBb1ltQVNPVExNK1ppbVY4OC93 +OVBqUmtMQytsQkpMZkxDbXZ2R0d6ZzQKLS0tIGlGNktqWDFZMDZaYTVFTUIyNmZD +dnY1aHZGMFRpb2djMmViSU5qNkJ0M1EKtRkajujtLCgCZkPRQEGanAavNj/GQc/g +xQemDwYveQVheTyc9zA= +-----END AGE ENCRYPTED FILE----- +``` + +Once you have the encrypted contents, you can decrypt it by: + +1. Run `./shared/keys/decrypt-age.py` from the infrastructure repo checkout +2. Paste the encrypted message in your terminal +3. Press enter, and then `Ctrl+D` +4. You'll see the decrypted output! + +Alternatively, you can also run `./shared/keys/decrypt-age.py ` +if the encrypted message is stored in a file \ No newline at end of file diff --git a/docs/howto/support/index.md b/docs/howto/support/index.md new file mode 100644 index 0000000000..5f1c65dfc3 --- /dev/null +++ b/docs/howto/support/index.md @@ -0,0 +1,11 @@ +# Support + +This section lists various tasks that engineers might do as part of support +requests. + + +```{toctree} +:maxdepth: 2 + +decrypt-age +``` \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index e1d18b6f72..f8358c3f0b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -36,6 +36,7 @@ howto/k8s/index.md howto/configure/auth-management/index.md howto/configure/update-env howto/cloud/new-gcp-project +howto/support/index ``` ## Topic guides diff --git a/docs/reference/tools.md b/docs/reference/tools.md index 709e5162cd..1f09b6dadd 100644 --- a/docs/reference/tools.md +++ b/docs/reference/tools.md @@ -71,6 +71,7 @@ Helm is used in two ways: the rendered templates with a k8s api-server. This is an excellent lightweight test of a Helm chart in a CI system. +(tools:sops)= ### [`sops`](https://github.com/mozilla/sops/) In line with 2i2c's [Customer Right to Replicate](https://2i2c.org/right-to-replicate/), @@ -104,6 +105,7 @@ issues](../howto/k8s/node-administration.md). ### Tips +(tools:gcloud:auth)= #### Authentication `gcloud` has two authentication flows, and that can get quite confusing since we diff --git a/shared/keys/decrypt-age.py b/shared/keys/decrypt-age.py new file mode 100755 index 0000000000..0187d41f8e --- /dev/null +++ b/shared/keys/decrypt-age.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +""" +Simple utility to decrypt secrets sent to `support@2i2c.org` via `age` +""" +import argparse +import pathlib +import subprocess +import sys +import tempfile +from contextlib import contextmanager + + +@contextmanager +def decrypt_age_private_key(): + """ + Decrypt our age private key, which is encrypted with sops + """ + age_private_key = pathlib.Path(__file__).parent.joinpath("enc-age-private.key") + + with tempfile.NamedTemporaryFile() as f: + subprocess.check_call( + ["sops", "--output", f.name, "--decrypt", age_private_key] + ) + + yield f.name + + +def decrypt_content(encrypted_contents): + """ + Decrypt contents + """ + with decrypt_age_private_key() as age_key: + cmd = ["age", "--decrypt", "--identity", age_key] + + subprocess.run(cmd, input=encrypted_contents, check=True) + + +def main(): + argparser = argparse.ArgumentParser() + argparser.add_argument( + "encrypted_file", + nargs="?", + help="Path to age-encrypted file sent by user. Leave empty to read from stdin", + ) + args = argparser.parse_args() + + if not args.encrypted_file: + # No file specified + print("Paste the encrypted file contents, hit enter and then press Ctrl+D") + encrypted_contents = sys.stdin.read().encode() + else: + # rb so it doesn't try to decode to utf-8, in case we have a non-armored file + with open(args.encrypted_file, "rb") as f: + encrypted_contents = f.read() + + decrypt_content(encrypted_contents) + + +main() diff --git a/shared/keys/enc-age-private.key b/shared/keys/enc-age-private.key new file mode 100644 index 0000000000..973b2cd16d --- /dev/null +++ b/shared/keys/enc-age-private.key @@ -0,0 +1,21 @@ +{ + "data": "ENC[AES256_GCM,data:5ndjbuQdvmWSp+jMIV9YNqlsp/4OQH+wPZfoM2HsmP5qwACdL/pismiXp9ZJDuV4TzritzpV75Ghg5q0izhIIiGuno2tDj4vEOOFuLlQWQ4x4facpZLDCny4wufj74l6uBokv9+QH/fw8l0twhUmqDp5AKU8w6ZwF46SaZBZYEdEWA/Jfc6S2rTDlNf+RlJLMqsuYYYkIoFw1Wq1hJ9AKBnPnb5a4B1a/9HmvrBZrX1G7eLGJWuCYMvIDtsH,iv:wA71gaG+8XDRSPXRnoyGYyOviOIrMBF682/THgPzYy0=,tag:T5D/lMPhDXFgqZDF5hsuPA==,type:str]", + "sops": { + "kms": null, + "gcp_kms": [ + { + "resource_id": "projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs", + "created_at": "2022-09-09T17:43:24Z", + "enc": "CiQA4OM7eGpDfkXE75IRW8hLTcQq88chS6bWiSmHG9z+U28cjpQSSQDuy/p8JMXTL0u6q2T+dD2SvpVsXYs88vYLJ2v04W+JUKmXH+a7cdOfeND78aJBWf0XxwEdJxTpVS39xHHwpgsewerC+M/Rfzw=" + } + ], + "azure_kv": null, + "hc_vault": null, + "age": null, + "lastmodified": "2022-09-09T17:43:24Z", + "mac": "ENC[AES256_GCM,data:GLd3kq0KYade+r6sDuTsGMYl9wQMqWpplIPxun5W0qVi+2peS4+TD/rxeE7YCw/og/stdERcFfFL4Dwh5qLI49dlgHe/llpQGCt7Spt13d44ex/Bv/pYKUyfdO7OKjIrLLbG1dymqD2OvkmN/lyr+29INa1sU+HvMHZHNtGo9wo=,iv:0O/fHXvo4p42Qim1B10lwZmaE4jnOb737/YlC7L2OvI=,tag:yTY8DN157AumtIQRIw9xsg==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.7.3" + } +} \ No newline at end of file