Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6c6c88e6e | ||
|
|
ee33702463 | ||
|
|
8b6995e9ec | ||
|
|
36ba8f0fcb | ||
|
|
bfb560ec50 |
@@ -73,15 +73,17 @@ var createKsCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ksSource string
|
ksSource string
|
||||||
ksPath string
|
ksPath string
|
||||||
ksPrune bool
|
ksPrune bool
|
||||||
ksDependsOn []string
|
ksDependsOn []string
|
||||||
ksValidation string
|
ksValidation string
|
||||||
ksHealthCheck []string
|
ksHealthCheck []string
|
||||||
ksHealthTimeout time.Duration
|
ksHealthTimeout time.Duration
|
||||||
ksSAName string
|
ksSAName string
|
||||||
ksSANamespace string
|
ksSANamespace string
|
||||||
|
ksDecryptionProvider string
|
||||||
|
ksDecryptionSecret string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -94,6 +96,8 @@ func init() {
|
|||||||
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied")
|
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied")
|
||||||
createKsCmd.Flags().StringVar(&ksSAName, "sa-name", "", "service account name")
|
createKsCmd.Flags().StringVar(&ksSAName, "sa-name", "", "service account name")
|
||||||
createKsCmd.Flags().StringVar(&ksSANamespace, "sa-namespace", "", "service account namespace")
|
createKsCmd.Flags().StringVar(&ksSANamespace, "sa-namespace", "", "service account namespace")
|
||||||
|
createKsCmd.Flags().StringVar(&ksDecryptionProvider, "decryption-provider", "", "enables secrets decryption, provider can be 'sops'")
|
||||||
|
createKsCmd.Flags().StringVar(&ksDecryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
|
||||||
createCmd.AddCommand(createKsCmd)
|
createCmd.AddCommand(createKsCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +182,21 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ksDecryptionProvider != "" {
|
||||||
|
if !utils.containsItemString(supportedDecryptionProviders, ksDecryptionProvider) {
|
||||||
|
return fmt.Errorf("decryption provider %s is not supported, can be %v",
|
||||||
|
ksDecryptionProvider, supportedDecryptionProviders)
|
||||||
|
}
|
||||||
|
|
||||||
|
kustomization.Spec.Decryption = &kustomizev1.Decryption{
|
||||||
|
Provider: ksDecryptionProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ksDecryptionSecret != "" {
|
||||||
|
kustomization.Spec.Decryption.SecretRef = &corev1.LocalObjectReference{Name: ksDecryptionSecret}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if export {
|
if export {
|
||||||
return exportKs(kustomization)
|
return exportKs(kustomization)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,11 +104,12 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultComponents = []string{"source-controller", "kustomize-controller", "helm-controller", "notification-controller"}
|
defaultComponents = []string{"source-controller", "kustomize-controller", "helm-controller", "notification-controller"}
|
||||||
defaultVersion = "latest"
|
defaultVersion = "latest"
|
||||||
defaultNamespace = "gitops-system"
|
defaultNamespace = "gitops-system"
|
||||||
defaultNotification = "notification-controller"
|
defaultNotification = "notification-controller"
|
||||||
supportedArch = []string{"arm64", "amd64"}
|
supportedArch = []string{"arm64", "amd64"}
|
||||||
|
supportedDecryptionProviders = []string{"sops"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ gotk create kustomization [name] [flags]
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--decryption-provider string enables secrets decryption, provider can be 'sops'
|
||||||
|
--decryption-secret string set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption
|
||||||
--depends-on stringArray Kustomization that must be ready before this Kustomization can be applied
|
--depends-on stringArray Kustomization that must be ready before this Kustomization can be applied
|
||||||
--health-check stringArray workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'
|
--health-check stringArray workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'
|
||||||
--health-check-timeout duration timeout of health checking operations (default 2m0s)
|
--health-check-timeout duration timeout of health checking operations (default 2m0s)
|
||||||
|
|||||||
166
docs/guides/mozilla-sops.md
Normal file
166
docs/guides/mozilla-sops.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# Manage Kubernetes secrets with Mozilla SOPS
|
||||||
|
|
||||||
|
In order to store secrets safely in a public or private Git repository, you can use
|
||||||
|
Mozilla's [SOPS](https://github.com/mozilla/sops) CLI to encrypt
|
||||||
|
Kubernetes secrets with OpenPGP, AWS KMS, GCP KMS and Azure Key Vault.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
To follow this guide you'll need a Kubernetes cluster with the GitOps
|
||||||
|
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):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
brew install gnupg sops
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generate a GPG key
|
||||||
|
|
||||||
|
Generate a GPG key with OpenPGP without specifying a passphrase:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ gpg --full-generate-key
|
||||||
|
|
||||||
|
Real name: stefanprodan
|
||||||
|
Email address: stefanprodan@users.noreply.github.com
|
||||||
|
Comment:
|
||||||
|
You selected this USER-ID:
|
||||||
|
"stefanprodan <stefanprodan@users.noreply.github.com>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Retrieve the GPG key ID (second row of the sec column):
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ gpg --list-secret-keys stefanprodan@users.noreply.github.com
|
||||||
|
|
||||||
|
sec rsa3072 2020-09-06 [SC]
|
||||||
|
1F3D1CED2F865F5E59CA564553241F147E7C5FA4
|
||||||
|
```
|
||||||
|
|
||||||
|
Export the public and private keypair from your local GPG keyring and
|
||||||
|
create a Kubernetes secret named `sops-gpg` in the `gitops-system` namespace:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gpg --export-secret-keys \
|
||||||
|
--armor 1F3D1CED2F865F5E59CA564553241F147E7C5FA4 |
|
||||||
|
kubectl create secret generic sops-gpg \
|
||||||
|
--namespace=gitops-system \
|
||||||
|
--from-file=sops.asc=/dev/stdin
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encrypt secrets
|
||||||
|
|
||||||
|
Generate a Kubernetes secret manifest with kubectl:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
kubectl -n default create secret generic basic-auth \
|
||||||
|
--from-literal=user=admin \
|
||||||
|
--from-literal=password=change-me \
|
||||||
|
--dry-run=client \
|
||||||
|
-o yaml > basic-auth.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Encrypt the secret with sops using your GPG key:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sops --encrypt \
|
||||||
|
--pgp=1F3D1CED2F865F5E59CA564553241F147E7C5FA4 \
|
||||||
|
--encrypted-regex '^(data|stringData)$' \
|
||||||
|
--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.
|
||||||
|
|
||||||
|
## Configure secrets decryption
|
||||||
|
|
||||||
|
Registry the Git repository on your cluster:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gotk create source git my-secrets \
|
||||||
|
--url=https://github.com/my-org/my-secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a kustomization for reconciling the secrets on the cluster:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gotk 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.
|
||||||
|
|
||||||
|
!!! hint KMS
|
||||||
|
When using AWS/GCP KMS or Azure Key Vault, you'll have to bind an IAM Role
|
||||||
|
with read access to the KMS keys to the `default` service account of the
|
||||||
|
`gitops-system` namespace for kustomize-controller to be able to fetch
|
||||||
|
keys from KMS.
|
||||||
|
|
||||||
|
## GitOps workflow
|
||||||
|
|
||||||
|
A cluster admin should create the Kubernetes secret with the PGP keys on each cluster and
|
||||||
|
add the GitRepository/Kustomization manifests to the fleet repository.
|
||||||
|
|
||||||
|
Git repository manifest:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1alpha1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
name: my-secrets
|
||||||
|
namespace: gitops-system
|
||||||
|
spec:
|
||||||
|
interval: 1m
|
||||||
|
url: https://github.com/my-org/my-secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
Kustomization manifest:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1alpha1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: my-secrets
|
||||||
|
namespace: gitops-system
|
||||||
|
spec:
|
||||||
|
interval: 10m0s
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: my-secrets
|
||||||
|
path: ./
|
||||||
|
prune: true
|
||||||
|
decryption:
|
||||||
|
provider: sops
|
||||||
|
secretRef:
|
||||||
|
name: sops-gpg
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! hint
|
||||||
|
You can generate the above manifests using `gotk create <kind> --export > manifest.yaml`.
|
||||||
|
|
||||||
|
Assuming a team member wants to deploy an application that needs to connect
|
||||||
|
to a database using a username and password, they'll be doing the following:
|
||||||
|
|
||||||
|
* create a Kubernetes Secret manifest locally with the db credentials e.g. `db-auth.yaml`
|
||||||
|
* encrypt the secret `data` field with sops
|
||||||
|
* create a Kubernetes Deployment manifest for the app e.g. `app-deployment.yaml`
|
||||||
|
* add the Secret to the Deployment manifest as a [volume mount or env var](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets)
|
||||||
|
* commit the manifests `db-auth.yaml` and `app-deployment.yaml` to a Git repository that's being synced by the GitOps toolkit controllers
|
||||||
|
|
||||||
|
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
|
||||||
|
* kubelet creates the pods and mounts the secret as a volume or env variable inside the app container
|
||||||
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ go 1.14
|
|||||||
require (
|
require (
|
||||||
github.com/blang/semver v3.5.1+incompatible
|
github.com/blang/semver v3.5.1+incompatible
|
||||||
github.com/fluxcd/helm-controller/api v0.0.7
|
github.com/fluxcd/helm-controller/api v0.0.7
|
||||||
github.com/fluxcd/kustomize-controller/api v0.0.9
|
github.com/fluxcd/kustomize-controller/api v0.0.10
|
||||||
github.com/fluxcd/pkg/git v0.0.6
|
github.com/fluxcd/pkg/git v0.0.6
|
||||||
github.com/fluxcd/pkg/ssh v0.0.5
|
github.com/fluxcd/pkg/ssh v0.0.5
|
||||||
github.com/fluxcd/pkg/untar v0.0.5
|
github.com/fluxcd/pkg/untar v0.0.5
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -113,8 +113,8 @@ github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
|
|||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fluxcd/helm-controller/api v0.0.7 h1:aidjXvcklClH8omhYqiKswZ+MS6t8knOpUacsuESue8=
|
github.com/fluxcd/helm-controller/api v0.0.7 h1:aidjXvcklClH8omhYqiKswZ+MS6t8knOpUacsuESue8=
|
||||||
github.com/fluxcd/helm-controller/api v0.0.7/go.mod h1:KlzwTkpphQxulgWBwCl/uxfBU0QxK/X+w4YcJqGy/1c=
|
github.com/fluxcd/helm-controller/api v0.0.7/go.mod h1:KlzwTkpphQxulgWBwCl/uxfBU0QxK/X+w4YcJqGy/1c=
|
||||||
github.com/fluxcd/kustomize-controller/api v0.0.9 h1:hHhKT+YZUFgw/lWa44++8t0OO+ScXhrzn33Pt/1OJe0=
|
github.com/fluxcd/kustomize-controller/api v0.0.10 h1:dhkTOg3LzNQwRL+lO0YlzOP7AhdpZdghUQNXYhvfiYU=
|
||||||
github.com/fluxcd/kustomize-controller/api v0.0.9/go.mod h1:88m3p6xY3J2pjh5OsL3ANy7PkyA93KiqAJE58JMQyoc=
|
github.com/fluxcd/kustomize-controller/api v0.0.10/go.mod h1:88m3p6xY3J2pjh5OsL3ANy7PkyA93KiqAJE58JMQyoc=
|
||||||
github.com/fluxcd/pkg/git v0.0.6 h1:4qktw8M3zj98MAs4ny6qSi36sYvTiI1czif5FqlQl4o=
|
github.com/fluxcd/pkg/git v0.0.6 h1:4qktw8M3zj98MAs4ny6qSi36sYvTiI1czif5FqlQl4o=
|
||||||
github.com/fluxcd/pkg/git v0.0.6/go.mod h1:9AI9yPkb2ruIcE70moVG3WhunA2/RAMJPc3rtoH8QFE=
|
github.com/fluxcd/pkg/git v0.0.6/go.mod h1:9AI9yPkb2ruIcE70moVG3WhunA2/RAMJPc3rtoH8QFE=
|
||||||
github.com/fluxcd/pkg/ssh v0.0.5 h1:rnbFZ7voy2JBlUfMbfyqArX2FYaLNpDhccGFC3qW83A=
|
github.com/fluxcd/pkg/ssh v0.0.5 h1:rnbFZ7voy2JBlUfMbfyqArX2FYaLNpDhccGFC3qW83A=
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
- github.com/fluxcd/kustomize-controller/config//crd?ref=v0.0.9
|
- github.com/fluxcd/kustomize-controller/config//crd?ref=v0.0.10
|
||||||
- github.com/fluxcd/kustomize-controller/config//manager?ref=v0.0.9
|
- github.com/fluxcd/kustomize-controller/config//manager?ref=v0.0.10
|
||||||
patchesJson6902:
|
patchesJson6902:
|
||||||
- target:
|
- target:
|
||||||
group: apps
|
group: apps
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ nav:
|
|||||||
- Setup Notifications: guides/notifications.md
|
- Setup Notifications: guides/notifications.md
|
||||||
- Setup Webhook Receivers: guides/webhook-receivers.md
|
- Setup Webhook Receivers: guides/webhook-receivers.md
|
||||||
- Sealed Secrets: guides/sealed-secrets.md
|
- Sealed Secrets: guides/sealed-secrets.md
|
||||||
|
- Mozilla SOPS: guides/mozilla-sops.md
|
||||||
- Toolkit Components:
|
- Toolkit Components:
|
||||||
- Source Controller:
|
- Source Controller:
|
||||||
- Overview: components/source/controller.md
|
- Overview: components/source/controller.md
|
||||||
|
|||||||
Reference in New Issue
Block a user