feat: use age instead of gpg for sops (#153)

* feat: use age instead of gpg

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: update comment in config env

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: set some debug output in configure.sh

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: use /Users/devin instead of full path

Signed-off-by: Devin Buhl <devin@buhl.casa>

* fix: check if BOOTSTRAP_AGE_PUBLIC_KEY starts with age

Signed-off-by: Devin Buhl <devin@buhl.casa>
This commit is contained in:
Devin Buhl authored and GitHub committed 2021-11-25 07:34:46 -05:00
1 parent ab48ebb928
commit 35d41ca8db
9 files changed
+62 -92

No files matched your search

+3 -6
View File
@@ -19,12 +19,9 @@ export BOOTSTRAP_METALLB_LB_RANGE=""
# The load balancer IP for traefik, choose from one of the available IPs above
# e.g. 192.168.1.220
export BOOTSTRAP_METALLB_TRAEFIK_ADDR=""
# Your personal pgp key
# e.g. 772154FFF783DE317KLCA0EC77149AC618D75581
export BOOTSTRAP_PERSONAL_KEY_FP=""
# The flux pgp key
# e.g. AB675CE4CC64251G3S9AE1DAA88ARRTY2C009E2D
export BOOTSTRAP_FLUX_KEY_FP=""
# Age Public Key - string should start with age
# e.g. age15uzrw396e67z9wdzsxzdk7ka0g2gr3l460e0slaea563zll3hdfqwqxdta
export BOOTSTRAP_AGE_PUBLIC_KEY=""
#
# Ansible related variables
+2 -1
View File
@@ -1,4 +1,5 @@
#shellcheck disable=SC2148,SC2155
export KUBECONFIG=$(expand_path ./provision/kubeconfig)
export ANSIBLE_CONFIG=$(expand_path ./ansible.cfg)
export GPG_TTY=$(tty)
export ANSIBLE_HOST_KEY_CHECKING="False"
export SOPS_AGE_KEY_FILE=$(expand_path ~/.config/sops/age/keys.txt)
+1
View File
@@ -8,6 +8,7 @@ kubeconfig
# vscode-sops
.decrypted~*.yaml
.config.env
*.agekey
# Ansible
xanmanning.k3s*
# Terraform
+38 -66
View File
@@ -2,7 +2,7 @@
Highly opinionated template for deploying a single [k3s](https://k3s.io) cluster with [Ansible](https://www.ansible.com) and [Terraform](https://www.terraform.io) backed by [Flux](https://toolkit.fluxcd.io/) and [SOPS](https://toolkit.fluxcd.io/guides/mozilla-sops/).
The purpose here is to showcase how you can deploy an entire Kubernetes cluster and show it off to the world using the [GitOps](https://www.weave.works/blog/what-is-gitops-really) tool [Flux](https://toolkit.fluxcd.io/). When completed, your Git repository will be driving the state of your Kubernetes cluster. In addition with the help of the [Ansible](https://github.com/ansible-collections/community.sops), [Terraform](https://github.com/carlpett/terraform-provider-sops) and [Flux](https://toolkit.fluxcd.io/guides/mozilla-sops/) SOPS integrations you'll be able to commit GPG encrypted secrets to your public repo.
The purpose here is to showcase how you can deploy an entire Kubernetes cluster and show it off to the world using the [GitOps](https://www.weave.works/blog/what-is-gitops-really) tool [Flux](https://toolkit.fluxcd.io/). When completed, your Git repository will be driving the state of your Kubernetes cluster. In addition with the help of the [Ansible](https://github.com/ansible-collections/community.sops), [Terraform](https://github.com/carlpett/terraform-provider-sops) and [Flux](https://toolkit.fluxcd.io/guides/mozilla-sops/) SOPS integrations you'll be able to commit Age encrypted secrets to your public repo.
## Overview
@@ -50,28 +50,27 @@ For provisioning the following tools will be used:
#### Required
| Tool | Purpose |
|--------------------------------------------------------------------|---------------------------------------------------------------------|
| [ansible](https://www.ansible.com) | Preparing Ubuntu for Kubernetes and installing k3s |
| [direnv](https://github.com/direnv/direnv) | Exports env vars based on present working directory |
| [flux](https://toolkit.fluxcd.io/) | Operator that manages your k8s cluster based on your Git repository |
| [gnupg](https://gnupg.org/) | Encrypts and signs your data |
| [go-task](https://github.com/go-task/task) | A task runner / simpler Make alternative written in Go |
| [ipcalc](http://jodies.de/ipcalc) | Used to verify settings in the configure script |
| [jq](https://stedolan.github.io/jq/) | Used to verify settings in the configure script |
| [kubectl](https://kubernetes.io/docs/tasks/tools/) | Allows you to run commands against Kubernetes clusters |
| [pinentry](https://gnupg.org/related_software/pinentry/index.html) | Allows GnuPG to read passphrases and PIN numbers |
| [sops](https://github.com/mozilla/sops) | Encrypts k8s secrets with GnuPG |
| [terraform](https://www.terraform.io) | Prepare a Cloudflare domain to be used with the cluster |
| Tool | Purpose |
|----------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| [ansible](https://www.ansible.com) | Preparing Ubuntu for Kubernetes and installing k3s |
| [direnv](https://github.com/direnv/direnv) | Exports env vars based on present working directory |
| [flux](https://toolkit.fluxcd.io/) | Operator that manages your k8s cluster based on your Git repository |
| [age](https://github.com/FiloSottile/age) | A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability. |
| [go-task](https://github.com/go-task/task) | A task runner / simpler Make alternative written in Go |
| [ipcalc](http://jodies.de/ipcalc) | Used to verify settings in the configure script |
| [jq](https://stedolan.github.io/jq/) | Used to verify settings in the configure script |
| [kubectl](https://kubernetes.io/docs/tasks/tools/) | Allows you to run commands against Kubernetes clusters |
| [sops](https://github.com/mozilla/sops) | Encrypts k8s secrets with Age |
| [terraform](https://www.terraform.io) | Prepare a Cloudflare domain to be used with the cluster |
#### Optional
| Tool | Purpose |
|--------------------------------------------------------------------|---------------------------------------------------------------------|
| [helm](https://helm.sh/) | Manage Kubernetes applications |
| [kustomize](https://kustomize.io/) | Template-free way to customize application configuration |
| [pre-commit](https://github.com/pre-commit/pre-commit) | Runs checks pre `git commit` |
| [prettier](https://github.com/prettier/prettier) | Prettier is an opinionated code formatter. |
| Tool | Purpose |
|--------------------------------------------------------|----------------------------------------------------------|
| [helm](https://helm.sh/) | Manage Kubernetes applications |
| [kustomize](https://kustomize.io/) | Template-free way to customize application configuration |
| [pre-commit](https://github.com/pre-commit/pre-commit) | Runs checks pre `git commit` |
| [prettier](https://github.com/prettier/prettier) | Prettier is an opinionated code formatter. |
### :warning:&nbsp; pre-commit
@@ -118,56 +117,31 @@ Clone the repo to you local workstation and `cd` into it.
:round_pushpin: **All of the below commands** are run on your **local** workstation, **not** on any of your cluster nodes.
### :closed_lock_with_key:&nbsp; Setting up GnuPG keys
### :closed_lock_with_key:&nbsp; Setting up Age
:round_pushpin: Here we will create a personal and a Flux GPG key. Using SOPS with GnuPG allows us to encrypt and decrypt secrets.
:round_pushpin: Here we will create a Age Private and Public key. Using SOPS with Age allows us to encrypt and decrypt secrets.
1. Create a Personal GPG Key, password protected, and export the fingerprint. It's **strongly encouraged** to back up this key somewhere safe so you don't lose it.
1. Create a Age Private / Public Key
```sh
export GPG_TTY=$(tty)
export PERSONAL_KEY_NAME="First name Last name (location) <email>"
gpg --batch --full-generate-key <<EOF
Key-Type: 1
Key-Length: 4096
Subkey-Type: 1
Subkey-Length: 4096
Expire-Date: 0
Name-Real: ${PERSONAL_KEY_NAME}
EOF
gpg --list-secret-keys "${PERSONAL_KEY_NAME}"
# pub rsa4096 2021-03-11 [SC]
# 772154FFF783DE317KLCA0EC77149AC618D75581
# uid [ultimate] k8s@home (Macbook) <k8s-at-home@gmail.com>
# sub rsa4096 2021-03-11 [E]
age-keygen -o age.agekey
```
2. Create a Flux GPG Key and export the fingerprint
2. Set up the directory for the Age key and move the Age file to it
```sh
export GPG_TTY=$(tty)
export FLUX_KEY_NAME="Cluster name (Flux) <email>"
gpg --batch --full-generate-key <<EOF
%no-protection
Key-Type: 1
Key-Length: 4096
Subkey-Type: 1
Subkey-Length: 4096
Expire-Date: 0
Name-Real: ${FLUX_KEY_NAME}
EOF
gpg --list-secret-keys "${FLUX_KEY_NAME}"
# pub rsa4096 2021-03-11 [SC]
# AB675CE4CC64251G3S9AE1DAA88ARRTY2C009E2D
# uid [ultimate] Home cluster (Flux) <k8s-at-home@gmail.com>
# sub rsa4096 2021-03-11 [E]
mkdir -p ~/.config/sops/age
mv age.agekey ~/.config/sops/age/keys.txt
```
3. You will need the Fingerprints in the configuration section below. For example, in the above steps you will need `772154FFF783DE317KLCA0EC77149AC618D75581` and `AB675CE4CC64251G3S9AE1DAA88ARRTY2C009E2D`
3. Export the `SOPS_AGE_KEY_FILE` variable in your `bashrc`, `zshrc` or `config.fish` and source it, e.g.
```sh
export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt
source ~/.bashrc
```
4. Fill out the Age public key in the `.config.env` under `BOOTSTRAP_AGE_PUBLIC_KEY`, **note** the public key should start with `age`...
### :cloud:&nbsp; Global Cloudflare API Key
@@ -248,14 +222,12 @@ flux --kubeconfig=./provision/kubeconfig check --pre
kubectl --kubeconfig=./provision/kubeconfig create namespace flux-system --dry-run=client -o yaml | kubectl --kubeconfig=./provision/kubeconfig apply -f -
```
3. Add the Flux GPG key in-order for Flux to decrypt SOPS secrets
3. Add the Age key in-order for Flux to decrypt SOPS secrets
```sh
source .config.env
gpg --export-secret-keys --armor "${BOOTSTRAP_FLUX_KEY_FP}" |
kubectl --kubeconfig=./provision/kubeconfig create secret generic sops-gpg \
--namespace=flux-system \
--from-file=sops.asc=/dev/stdin
cat ~/.config/sops/age/keys.txt |
kubectl -n default create secret generic sops-age \
--from-file=age.agekey=/dev/stdin
```
:round_pushpin: Variables defined in `./cluster/base/cluster-secrets.sops.yaml` and `./cluster/base/cluster-settings.sops.yaml` will be usable anywhere in your YAML manifests under `./cluster`
+1 -1
View File
@@ -16,7 +16,7 @@ spec:
decryption:
provider: sops
secretRef:
name: sops-gpg
name: sops-age
postBuild:
substitute: {}
substituteFrom:
+1 -1
View File
@@ -16,7 +16,7 @@ spec:
decryption:
provider: sops
secretRef:
name: sops-gpg
name: sops-age
postBuild:
substitute: {}
substituteFrom:
+11 -11
View File
@@ -31,7 +31,7 @@ main() {
verify_ansible_hosts
verify_metallb
verify_kubevip
verify_gpg
verify_age
verify_git_repository
verify_cloudflare
success
@@ -117,22 +117,22 @@ _has_valid_ip() {
fi
}
verify_gpg() {
_has_envar "BOOTSTRAP_PERSONAL_KEY_FP"
_has_envar "BOOTSTRAP_FLUX_KEY_FP"
verify_age() {
_has_envar "BOOTSTRAP_AGE_PUBLIC_KEY"
_has_envar "SOPS_AGE_KEY_FILE"
if ! gpg --list-keys "${BOOTSTRAP_PERSONAL_KEY_FP}" >/dev/null 2>&1; then
_log "ERROR" "Invalid Personal GPG FP ${BOOTSTRAP_PERSONAL_KEY_FP}"
if [[ ! "$BOOTSTRAP_AGE_PUBLIC_KEY" =~ ^age.* ]]; then
_log "ERROR" "BOOTSTRAP_AGE_PUBLIC_KEY does not start with age"
exit 1
else
_log "INFO" "Found Personal GPG Fingerprint '${BOOTSTRAP_PERSONAL_KEY_FP}'"
_log "INFO" "Age public key is in the correct format"
fi
if ! gpg --list-keys "${BOOTSTRAP_FLUX_KEY_FP}" >/dev/null 2>&1; then
_log "ERROR" "Invalid Flux GPG FP '${BOOTSTRAP_FLUX_KEY_FP}'"
if [[ ! -f ~/.config/sops/age/keys.txt ]]; then
_log "ERROR" "Unable to find Age file keys.txt in ~/.config/sops/age"
exit 1
else
_log "INFO" "Found Flux GPG Fingerprint '${BOOTSTRAP_FLUX_KEY_FP}'"
_log "INFO" "Found Age public key '${BOOTSTRAP_AGE_PUBLIC_KEY}'"
fi
}
@@ -141,7 +141,7 @@ verify_binaries() {
_has_binary "envsubst"
_has_binary "flux"
_has_binary "git"
_has_binary "gpg"
_has_binary "age"
_has_binary "helm"
_has_binary "ipcalc"
_has_binary "jq"
+4 -5
View File
@@ -2,10 +2,9 @@
creation_rules:
- path_regex: provision/.*\.sops\.ya?ml
unencrypted_regex: "^(kind)$"
pgp: >-
${BOOTSTRAP_PERSONAL_KEY_FP}
age: >-
${BOOTSTRAP_AGE_PUBLIC_KEY}
- path_regex: cluster/.*\.ya?ml
encrypted_regex: "^(data|stringData)$"
pgp: >-
${BOOTSTRAP_FLUX_KEY_FP},
${BOOTSTRAP_PERSONAL_KEY_FP}
age: >-
${BOOTSTRAP_AGE_PUBLIC_KEY}
+1 -1
View File
@@ -25,4 +25,4 @@ spec:
decryption:
provider: sops
secretRef:
name: sops-gpg
name: sops-age