mirror of
https://github.com/fluxcd/flux2.git
synced 2026-02-09 09:17:27 +00:00
Merge pull request #1027 from stealthybox/sops-gpg-batch
Improve SOPS GPG guide key management
This commit is contained in:
commit
69f38b8c77
1 changed files with 124 additions and 48 deletions
|
|
@ -11,7 +11,7 @@ toolkit controllers installed on it.
|
|||
Please see the [get started guide](../get-started/index.md)
|
||||
or the [installation guide](installation.md).
|
||||
|
||||
Install [gnupg](https://www.gnupg.org/) and [sops](https://github.com/mozilla/sops):
|
||||
Install [gnupg](https://www.gnupg.org/) and [SOPS](https://github.com/mozilla/sops):
|
||||
|
||||
```sh
|
||||
brew install gnupg sops
|
||||
|
|
@ -19,38 +19,144 @@ brew install gnupg sops
|
|||
|
||||
## Generate a GPG key
|
||||
|
||||
Generate a GPG key with OpenPGP without specifying a passphrase:
|
||||
Generate a GPG/OpenPGP key with no passphrase (`%no-protection`):
|
||||
|
||||
```console
|
||||
$ gpg --full-generate-key
|
||||
```sh
|
||||
export KEY_NAME="cluster0.yourdomain.com"
|
||||
export KEY_COMMENT="flux secrets"
|
||||
|
||||
Real name: stefanprodan
|
||||
Email address: stefanprodan@users.noreply.github.com
|
||||
Comment:
|
||||
You selected this USER-ID:
|
||||
"stefanprodan <stefanprodan@users.noreply.github.com>"
|
||||
gpg --batch --full-generate-key <<EOF
|
||||
%no-protection
|
||||
Key-Type: 1
|
||||
Key-Length: 4096
|
||||
Subkey-Type: 1
|
||||
Subkey-Length: 4096
|
||||
Expire-Date: 0
|
||||
Name-Comment: ${KEY_COMMENT}
|
||||
Name-Real: ${KEY_NAME}
|
||||
EOF
|
||||
```
|
||||
|
||||
Retrieve the GPG key ID (second row of the sec column):
|
||||
The above configuration creates an rsa4096 key that does not expire.
|
||||
For a full list of options to consider for your environment, see [Unattended GPG key generation](https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html).
|
||||
|
||||
```console
|
||||
$ gpg --list-secret-keys stefanprodan@users.noreply.github.com
|
||||
Retrieve the GPG key fingerprint (second row of the sec column):
|
||||
|
||||
sec rsa3072 2020-09-06 [SC]
|
||||
```sh
|
||||
gpg --list-secret-keys "${KEY_NAME}"
|
||||
|
||||
sec rsa4096 2020-09-06 [SC]
|
||||
1F3D1CED2F865F5E59CA564553241F147E7C5FA4
|
||||
```
|
||||
|
||||
Store the key fingerprint as an environment variable:
|
||||
|
||||
```sh
|
||||
export KEY_FP=1F3D1CED2F865F5E59CA564553241F147E7C5FA4
|
||||
```
|
||||
|
||||
Export the public and private keypair from your local GPG keyring and
|
||||
create a Kubernetes secret named `sops-gpg` in the `flux-system` namespace:
|
||||
|
||||
```sh
|
||||
gpg --export-secret-keys \
|
||||
--armor 1F3D1CED2F865F5E59CA564553241F147E7C5FA4 |
|
||||
gpg --export-secret-keys --armor "${KEY_FP}" |
|
||||
kubectl create secret generic sops-gpg \
|
||||
--namespace=flux-system \
|
||||
--from-file=sops.asc=/dev/stdin
|
||||
```
|
||||
|
||||
It's a good idea to back up this secret-key/K8s-Secret with a password manager or offline storage.
|
||||
Also consider deleting the secret decryption key from you machine:
|
||||
|
||||
```sh
|
||||
gpg --delete-secret-keys "${KEY_FP}"
|
||||
```
|
||||
|
||||
## Configure in-cluster secrets decryption
|
||||
|
||||
Register the Git repository on your cluster:
|
||||
|
||||
```sh
|
||||
flux create source git my-secrets \
|
||||
--url=https://github.com/my-org/my-secrets
|
||||
```
|
||||
|
||||
Create a kustomization for reconciling the secrets on the cluster:
|
||||
|
||||
```sh
|
||||
flux create kustomization my-secrets \
|
||||
--source=my-secrets \
|
||||
--path=./clusters/cluster0 \
|
||||
--prune=true \
|
||||
--interval=10m \
|
||||
--decryption-provider=sops \
|
||||
--decryption-secret=sops-gpg
|
||||
```
|
||||
|
||||
Note that the `sops-gpg` can contain more than one key, SOPS will try to decrypt the
|
||||
secrets by iterating over all the private keys until it finds one that works.
|
||||
|
||||
## Optional: Export the public key into the Git directory
|
||||
|
||||
Commit the public key to the repository so that team members who clone the repo can encrypt new files:
|
||||
|
||||
```sh
|
||||
gpg --export --armor "${KEY_FP}" > ./clusters/cluster0/.sops.pub.asc
|
||||
```
|
||||
|
||||
Check the file contents to ensure it's the public key before adding it to the repo and committing.
|
||||
|
||||
```sh
|
||||
git add ./clusters/cluster0/.sops.pub.asc
|
||||
git commit -am 'Share GPG public key for secrets generation'
|
||||
```
|
||||
|
||||
Team members can then import this key when they pull the Git repository:
|
||||
|
||||
```sh
|
||||
gpg --import ./clusters/cluster0/.sops.pub.asc
|
||||
```
|
||||
|
||||
!!! hint
|
||||
The public key is sufficient for creating brand new files.
|
||||
The secret key is required for decrypting and editing existing files because SOPS computes a MAC on all values.
|
||||
When using solely the public key to add or remove a field, the whole file should be deleted and recreated.
|
||||
|
||||
## Configure the Git directory for encryption
|
||||
|
||||
Write a [SOPS config file](https://github.com/mozilla/sops#using-sops-yaml-conf-to-select-kms-pgp-for-new-files) to the specific cluster or namespace directory used
|
||||
to store encrypted objects with this particular GPG key's fingerprint.
|
||||
|
||||
```yaml
|
||||
cat <<EOF > ./clusters/cluster0/.sops.yaml
|
||||
creation_rules:
|
||||
- path_regex: .*.yaml
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
pgp: ${KEY_FP}
|
||||
EOF
|
||||
```
|
||||
|
||||
This config applies recursively to all sub-directories.
|
||||
Multiple directories can use separate SOPS configs.
|
||||
Contributors using the `sops` CLI to create and encrypt files
|
||||
won't have to worry about specifying the proper key for the target cluster or namespace.
|
||||
|
||||
`encrypted_regex` helps encrypt the the proper `data` and `stringData` fields for Secrets.
|
||||
You may wish to add other fields if you are encrypting other types of Objects.
|
||||
|
||||
!!! hint
|
||||
Note that you should encrypt only the `data` or `stringData` section. Encrypting the Kubernetes
|
||||
secret metadata, kind or apiVersion is not supported by kustomize-controller.
|
||||
|
||||
Ignore all `.sops.yaml` files in a [`.sourceignore`](../components/source/gitrepositories#excluding-files) file at the root of your repo.
|
||||
|
||||
```sh
|
||||
touch .sourceignore
|
||||
echo '**/.sops.yaml' >> .sourceignore
|
||||
```
|
||||
|
||||
You can now commit your SOPS config.
|
||||
|
||||
## Encrypt secrets
|
||||
|
||||
Generate a Kubernetes secret manifest with kubectl:
|
||||
|
|
@ -63,47 +169,17 @@ kubectl -n default create secret generic basic-auth \
|
|||
-o yaml > basic-auth.yaml
|
||||
```
|
||||
|
||||
Encrypt the secret with sops using your GPG key:
|
||||
Encrypt the secret with SOPS using your GPG key:
|
||||
|
||||
```sh
|
||||
sops --encrypt \
|
||||
--pgp=1F3D1CED2F865F5E59CA564553241F147E7C5FA4 \
|
||||
--encrypted-regex '^(data|stringData)$' \
|
||||
--in-place basic-auth.yaml
|
||||
sops --encrypt --in-place basic-auth.yaml
|
||||
```
|
||||
|
||||
!!! hint
|
||||
Note that you should encrypt only the `data` section. Encrypting the Kubernetes
|
||||
secret metadata, kind or apiVersion is not supported by kustomize-controller.
|
||||
|
||||
You can now commit the encrypted secret to your Git repository.
|
||||
|
||||
!!! hint
|
||||
Note that you shouldn't apply the encrypted secrets onto the cluster with kubectl. SOPS encrypted secrets are designed to be consumed by kustomize-controller.
|
||||
|
||||
## Configure secrets decryption
|
||||
|
||||
Registry the Git repository on your cluster:
|
||||
|
||||
```sh
|
||||
flux create source git my-secrets \
|
||||
--url=https://github.com/my-org/my-secrets
|
||||
```
|
||||
|
||||
Create a kustomization for reconciling the secrets on the cluster:
|
||||
|
||||
```sh
|
||||
flux create kustomization my-secrets \
|
||||
--source=my-secrets \
|
||||
--prune=true \
|
||||
--interval=10m \
|
||||
--decryption-provider=sops \
|
||||
--decryption-secret=sops-gpg
|
||||
```
|
||||
|
||||
Note that the `sops-gpg` can contain more than one key, sops will try to decrypt the
|
||||
secrets by iterating over all the private keys until it finds one that works.
|
||||
|
||||
### Using various cloud providers
|
||||
|
||||
When using AWS/GCP KMS, you don't have to include the gpg `secretRef` under
|
||||
|
|
@ -210,5 +286,5 @@ Once the manifests have been pushed to the Git repository, the following happens
|
|||
|
||||
* source-controller pulls the changes from Git
|
||||
* kustomize-controller loads the GPG keys from the `sops-pgp` secret
|
||||
* kustomize-controller decrypts the Kubernetes secrets with sops and applies them on the cluster
|
||||
* kustomize-controller decrypts the Kubernetes secrets with SOPS and applies them on the cluster
|
||||
* kubelet creates the pods and mounts the secret as a volume or env variable inside the app container
|
||||
|
|
|
|||
Loading…
Reference in a new issue