Skip to content

Commit 54871b8

Browse files
review comments implementation
1 parent 21b61c1 commit 54871b8

File tree

11 files changed

+388
-24
lines changed

11 files changed

+388
-24
lines changed
File renamed without changes.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
apiVersion: v2
2-
name: site-secrets
3-
description: Orchestrating secrets across kubernetes clusters (global-site) using External SecretStore
2+
name: secretstore-gen-secrets
3+
description: Secret store backed External Secrets generator
44
type: application
55
version: 0.1.0
66
appVersion: "1.0"

components/secretstore-gen-secrets/templates/secrets.yaml.tmpl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
{{- $site := .Values.site }}
2-
{{- $secretStore := $site.secretStore }}
3-
{{- range $site.secrets }}
1+
{{- $secretStore := .Values.secretStore }}
2+
{{- range .Values.secrets }}
43
---
54
apiVersion: external-secrets.io/v1
65
kind: ExternalSecret
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1 @@
1-
site:
2-
name: uc-iad3-dev
3-
partition: uc-dev
4-
env: dev
5-
role: aio
6-
secretStore:
7-
kind: SecretStore
8-
name: vault
1+
---
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# External Secrets Guide
2+
3+
This guide explains how to automate Kubernetes secrets creation using
4+
external secret stores (Vault, AWS Secrets Manager, etc.) and ArgoCD
5+
components in the UnderStack environment.
6+
7+
------------------------------------------------------------------------
8+
9+
## TL;DR Quick Steps
10+
11+
1. **Assumption**: Credentials already exist in an external system
12+
(Vault, AWS Secrets Manager, PasswordSafe, etc.).
13+
2. **Install SecretStore** in the desired Kubernetes namespace.
14+
3. **Create ArgoCD component** in [apps/site/](https://github.com/rackerlabs/understack/tree/main/apps/site)
15+
to manage SecretStore + ExternalSecrets.
16+
4. **Configure `values.yaml`** to define secret templates.
17+
5. **Apply ArgoCD application** to deploy SecretStore and
18+
ExternalSecrets.
19+
20+
------------------------------------------------------------------------
21+
22+
## Assumptions
23+
24+
- Credentials are managed in external systems (Vault, AWS Secrets
25+
Manager, PasswordSafe).
26+
- Secrets must be pulled automatically into Kubernetes clusters.
27+
28+
------------------------------------------------------------------------
29+
30+
## Workflow
31+
32+
1. **Create an External SecretStore per Kubernetes namespace**.
33+
This links Kubernetes to the external backend (Vault, AWS Secrets
34+
Manager, etc.).
35+
36+
2. **Create an ArgoCD component** inside the site repo:
37+
Example:
38+
[nautobot-secretstore-gen-secrets.yaml](https://raw.githubusercontent.com/rackerlabs/understack/refs/heads/main/apps/site/nautobot-secretstore-gen-secrets.yaml)
39+
40+
This ArgoCD component performs two tasks:
41+
42+
- Installs the SecretStore.
43+
- Creates ExternalSecrets referencing the SecretStore.
44+
45+
3. **Deploy via Kustomize/Helm**
46+
47+
- One Helm chart installs the SecretStore pointing to the external
48+
backend system.
49+
- Another Helm chart creates the ExternalSecrets from that
50+
SecretStore.
51+
52+
4. **Configure `values.yaml`** with templates for secrets.
53+
54+
------------------------------------------------------------------------
55+
56+
## Example ArgoCD Component
57+
58+
``` yaml
59+
---
60+
component: nautobot-secrets
61+
componentNamespace: nautobot
62+
sources:
63+
- ref: understack
64+
path: 'components/secretstore-gen-secrets'
65+
helm:
66+
releaseName: nautobot-secrets
67+
valueFiles:
68+
- $deploy/{{.name}}/helm-configs/secretstore-nautobot-secrets.yaml
69+
ignoreMissingValueFiles: true
70+
- ref: deploy
71+
path: '{{.name}}/manifests/secret-store'
72+
```
73+
74+
------------------------------------------------------------------------
75+
76+
## Sample values.yaml
77+
78+
``` yaml
79+
# yaml-language-server: $schema=https://rackerlabs.understack.io/schema/component-secretstore-gen-secrets.schema.json
80+
---
81+
secretStore:
82+
kind: SecretStore
83+
name: pwsafe
84+
85+
secrets:
86+
- name: site1-token
87+
externalLinkAnnotationTemplate: "https://secretvault.example.com/credentials/373525"
88+
templateData:
89+
hostname: "{{ .hostname }}"
90+
username: "{{ .username }}"
91+
password: "{{ .password }}"
92+
token: "{{ .token }}"
93+
dataFrom:
94+
- extract:
95+
key: "373525"
96+
97+
- name: site2-token
98+
externalLinkAnnotationTemplate: "https://secretvault.example.com/credentials/373539"
99+
labels:
100+
token/type: mycustomlabel
101+
templateData:
102+
hostname: "{{ .hostname }}"
103+
username: "{{ .username }}"
104+
password: "{{ .password }}"
105+
token: "{{ .token }}"
106+
dataFrom:
107+
- extract:
108+
key: "373539"
109+
```
110+
111+
------------------------------------------------------------------------
112+
113+
## Summary
114+
115+
- **External systems** (Vault, AWS Secrets Manager, PasswordSafe) hold
116+
credentials.
117+
- **SecretStore** bridges Kubernetes to the external backend.
118+
- **ExternalSecrets** define the actual K8s secrets created from
119+
external data.
120+
- **ArgoCD components** ensure consistent automation of this workflow
121+
across namespaces.
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Secret store backed External Secrets generator Helm Chart Values",
4+
"description": "Schema for Secret store backed secrets generator Helm chart values.yaml configuration",
5+
"type": "object",
6+
"properties": {
7+
"secretStore": {
8+
"type": "object",
9+
"description": "Secret store backed secrets generator Secret Store configuration",
10+
"properties": {
11+
"kind": {
12+
"type": "string",
13+
"enum": ["ClusterSecretStore", "SecretStore"],
14+
"description": "Type of secret store - ClusterSecretStore or SecretStore for namespaced"
15+
},
16+
"name": {
17+
"type": "string",
18+
"description": "Name of the ClusterSecretStore or SecretStore to use"
19+
}
20+
},
21+
"required": ["kind", "name"],
22+
"additionalProperties": false
23+
},
24+
"secrets": {
25+
"type": "array",
26+
"description": "Array of External Secret configurations",
27+
"items": {
28+
"type": "object",
29+
"properties": {
30+
"name": {
31+
"type": "string",
32+
"description": "Name of the ExternalSecret and target Secret resource"
33+
},
34+
"externalLinkAnnotationTemplate": {
35+
"type": "string",
36+
"description": "Optional template for external link annotations on ExternalSecret resources"
37+
},
38+
"labels": {
39+
"type": "object",
40+
"description": "Labels to apply to both ExternalSecret and target Secret",
41+
"additionalProperties": {
42+
"type": "string"
43+
}
44+
},
45+
"refreshInterval": {
46+
"type": "string",
47+
"pattern": "^[0-9]+(s|m|h|d)$",
48+
"default": "1h",
49+
"description": "How often Secret store backed secrets generator refreshes this secret"
50+
},
51+
"templateType": {
52+
"type": "string",
53+
"default": "Opaque",
54+
"description": "Kubernetes secret type for the target secret",
55+
"enum": ["Opaque", "kubernetes.io/tls", "kubernetes.io/ssh-auth", "kubernetes.io/basic-auth", "kubernetes.io/dockerconfigjson", "kubernetes.io/service-account-token"]
56+
},
57+
"templateData": {
58+
"type": "object",
59+
"description": "Template data for constructing the target secret using Go templating",
60+
"additionalProperties": {
61+
"type": "string"
62+
}
63+
},
64+
"data": {
65+
"type": "array",
66+
"description": "Individual data mappings from remote secrets to target secret keys",
67+
"items": {
68+
"type": "object",
69+
"properties": {
70+
"secretKey": {
71+
"type": "string",
72+
"description": "Key name in the target Kubernetes secret"
73+
},
74+
"remoteRef": {
75+
"type": "object",
76+
"description": "Reference to the remote secret",
77+
"properties": {
78+
"key": {
79+
"type": "string",
80+
"description": "Key/ID of the remote secret"
81+
},
82+
"property": {
83+
"type": "string",
84+
"description": "Property/field within the remote secret"
85+
},
86+
"conversionStrategy": {
87+
"type": "string",
88+
"default": "Default",
89+
"enum": ["Default", "Unicode"],
90+
"description": "Strategy for converting the secret value"
91+
},
92+
"decodingStrategy": {
93+
"type": "string",
94+
"default": "None",
95+
"enum": ["None", "Base64", "Base64URL", "Auto"],
96+
"description": "Strategy for decoding the secret value"
97+
},
98+
"metadataPolicy": {
99+
"type": "string",
100+
"default": "None",
101+
"enum": ["None", "Fetch"],
102+
"description": "Policy for handling secret metadata"
103+
}
104+
},
105+
"required": ["key"],
106+
"additionalProperties": false
107+
}
108+
},
109+
"required": ["secretKey", "remoteRef"],
110+
"additionalProperties": false
111+
}
112+
},
113+
"dataFrom": {
114+
"type": "array",
115+
"description": "Bulk data extraction from remote secrets",
116+
"items": {
117+
"type": "object",
118+
"properties": {
119+
"extract": {
120+
"type": "object",
121+
"description": "Extract configuration for bulk secret retrieval",
122+
"properties": {
123+
"key": {
124+
"type": "string",
125+
"description": "Key/ID of the remote secret to extract from"
126+
},
127+
"property": {
128+
"type": "string",
129+
"description": "Specific property to extract (optional)"
130+
},
131+
"conversionStrategy": {
132+
"type": "string",
133+
"default": "Default",
134+
"enum": ["Default", "Unicode"],
135+
"description": "Strategy for converting the secret values"
136+
},
137+
"decodingStrategy": {
138+
"type": "string",
139+
"default": "None",
140+
"enum": ["None", "Base64", "Base64URL", "Auto"],
141+
"description": "Strategy for decoding the secret values"
142+
},
143+
"metadataPolicy": {
144+
"type": "string",
145+
"default": "None",
146+
"enum": ["None", "Fetch"],
147+
"description": "Policy for handling secret metadata"
148+
}
149+
},
150+
"required": ["key"],
151+
"additionalProperties": false
152+
},
153+
"find": {
154+
"type": "object",
155+
"description": "Find configuration for pattern-based secret discovery",
156+
"properties": {
157+
"path": {
158+
"type": "string",
159+
"description": "Path pattern to search for secrets"
160+
},
161+
"name": {
162+
"type": "object",
163+
"description": "Name pattern configuration",
164+
"properties": {
165+
"regexp": {
166+
"type": "string",
167+
"description": "Regular expression for matching secret names"
168+
}
169+
},
170+
"additionalProperties": false
171+
},
172+
"tags": {
173+
"type": "object",
174+
"description": "Tag filters for finding secrets",
175+
"additionalProperties": {
176+
"type": "string"
177+
}
178+
}
179+
},
180+
"additionalProperties": false
181+
},
182+
"sourceRef": {
183+
"type": "object",
184+
"description": "Reference to a different secret store for this data source",
185+
"properties": {
186+
"storeRef": {
187+
"type": "object",
188+
"properties": {
189+
"name": {
190+
"type": "string",
191+
"description": "Name of the secret store"
192+
},
193+
"kind": {
194+
"type": "string",
195+
"enum": ["ClusterSecretStore", "SecretStore"],
196+
"description": "Kind of secret store"
197+
}
198+
},
199+
"required": ["name", "kind"],
200+
"additionalProperties": false
201+
}
202+
},
203+
"additionalProperties": false
204+
}
205+
},
206+
"anyOf": [
207+
{"required": ["extract"]},
208+
{"required": ["find"]}
209+
],
210+
"additionalProperties": false
211+
}
212+
}
213+
},
214+
"required": ["name"],
215+
"anyOf": [
216+
{"required": ["data"]},
217+
{"required": ["dataFrom"]},
218+
{"required": ["templateData"]}
219+
],
220+
"additionalProperties": false
221+
}
222+
}
223+
},
224+
"required": ["secretStore", "secrets"],
225+
"additionalProperties": false
226+
}

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ nav:
134134
- deploy-guide/config-dex.md
135135
- deploy-guide/config-openstack.md
136136
- deploy-guide/secrets-eso-setup.md
137+
- deploy-guide/generate-external-secrets.md
137138
- deploy-guide/openstack-svc-users.md
138139
- deploy-guide/auth.md
139140
- deploy-guide/config-argo-workflows.md

workflows/nautobot/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ resources:
99

1010
# noutobot secret
1111
- serviceaccounts/k8s-secret-events-nautobot.yaml
12+
- serviceaccounts/k8s-job-create.yaml
1213
- eventsources/k8s-secret-nautobot-token.yaml
1314
- sensors/k8s-nautobot-secret.yaml

0 commit comments

Comments
 (0)