Skip to content

Commit 2114a6c

Browse files
cardoeskrobul
andcommitted
feat(openstack): share service acct credentials via ESO
Utilize the External Secrets Operator to define the OpenStack service account credentials that OpenStack Helm needs to work with Keystone service accounts for the various OpenStack services. This allows one cluster to run Keystone and another to run the OpenStack services and to utilize the ESO operator to keep the credentials in sync between the two. Co-authored-by: Marek Skrobacki <[email protected]>
1 parent 86a8a7d commit 2114a6c

File tree

17 files changed

+676
-9
lines changed

17 files changed

+676
-9
lines changed

components/cinder/values.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ dependencies:
126126
- cinder-ks-endpoints
127127

128128
manifests:
129-
secret_keystone: true
130129
job_backup_storage_init: false
131130
job_bootstrap: false
132131
job_clean: false
@@ -141,6 +140,12 @@ manifests:
141140
secret_registry: false
142141
service_ingress_api: false
143142
deployment_backup: false
143+
# We set the `secret_keystone` and `secret_ks_etc` to false in order to disable
144+
# Kubernetes section generation in OpenStack Helm, because we want those
145+
# to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled
146+
# that is later consumed via components/openstack helm chart
147+
secret_keystone: false
148+
secret_ks_etc: false
144149

145150
annotations:
146151
# we need to modify the annotations on OpenStack Helm

components/glance/values.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,13 @@ manifests:
109109
job_image_repo_sync: false
110110
pod_rally_test: false
111111
secret_db: false
112-
secret_keystone: true
113112
service_ingress_api: false
113+
# We set the `secret_keystone` and `secret_ks_etc` to false in order to disable
114+
# Kubernetes section generation in OpenStack Helm, because we want those
115+
# to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled
116+
# that is later consumed via components/openstack helm chart
117+
secret_keystone: false
118+
secret_ks_etc: false
114119

115120
annotations:
116121
# we need to modify the annotations on OpenStack Helm

components/ironic/values.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ manifests:
192192
secret_rabbitmq: false
193193
secret_registry: false
194194
service_ingress_api: false
195+
# We set the `secret_keystone` and `secret_ks_etc` to false in order to disable
196+
# Kubernetes section generation in OpenStack Helm, because we want those
197+
# to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled
198+
# that is later consumed via components/openstack helm chart
199+
secret_keystone: false
200+
secret_ks_etc: false
195201

196202
pod:
197203
mounts:

components/keystone/values.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,16 @@ manifests:
304304
job_rabbit_init: false
305305
pod_rally_test: false
306306
secret_db: false
307-
secret_keystone: true
308307
service_ingress_api: false
309308
# these next two we create ourselves to avoid helm hooks issues
310309
secret_credential_keys: false
311310
secret_fernet_keys: false
311+
# We set the `secret_keystone` and `secret_ks_etc` to false in order to disable
312+
# Kubernetes section generation in OpenStack Helm, because we want those
313+
# to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled
314+
# that is later consumed via components/openstack helm chart
315+
secret_keystone: false
316+
secret_ks_etc: false
312317

313318
annotations:
314319
# we need to modify the annotations on OpenStack Helm

components/neutron/values.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ manifests:
175175
job_rabbit_init: false
176176
pod_rally_test: false
177177
secret_db: false
178-
secret_keystone: true
179178
# OVN has its own pieces and does not need the following:
180179
# - neutron-dhcp-agent (OVN's does not work with baremetal/ironic currently)
181180
# - neutron-l3-agent
@@ -197,6 +196,12 @@ manifests:
197196
daemonset_netns_cleanup_cron: false
198197
deployment_ironic_agent: true
199198
service_ingress_server: false
199+
# We set the `secret_keystone` and `secret_ks_etc` to false in order to disable
200+
# Kubernetes section generation in OpenStack Helm, because we want those
201+
# to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled
202+
# that is later consumed via components/openstack helm chart
203+
secret_keystone: false
204+
secret_ks_etc: false
200205

201206
annotations:
202207
# we need to modify the annotations on OpenStack Helm

components/nova/values.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,16 @@ manifests:
165165
secret_db_api: true
166166
secret_db_cell0: true
167167
secret_db: true
168-
secret_keystone: true
169168
service_ingress_metadata: false
170169
service_ingress_osapi: false
171170
daemonset_compute: false
172171
statefulset_compute_ironic: true
172+
# We set the `secret_keystone` and `secret_ks_etc` to false in order to disable
173+
# Kubernetes section generation in OpenStack Helm, because we want those
174+
# to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled
175+
# that is later consumed via components/openstack helm chart
176+
secret_keystone: false
177+
secret_ks_etc: false
173178

174179
annotations:
175180
# we need to modify the annotations on OpenStack Helm

components/octavia/values.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,13 @@ manifests:
9191
job_rabbit_init: false
9292
pod_rally_test: false
9393
secret_db: true
94-
secret_keystone: true
9594
service_ingress_api: false
95+
# We set the `secret_keystone` and `secret_ks_etc` to false in order to disable
96+
# Kubernetes section generation in OpenStack Helm, because we want those
97+
# to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled
98+
# that is later consumed via components/openstack helm chart
99+
secret_keystone: false
100+
secret_ks_etc: false
96101

97102
annotations:
98103
# we need to modify the annotations on OpenStack Helm
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
{{- if .Values.keystoneServiceUsers.enabled }}
2+
{{- range $serviceName, $users := .Values.keystoneServiceUsers.services }}
3+
{{- range $_, $user := $users }}
4+
{{/* special override for the admin user since its in the bootstrap domain of default */}}
5+
{{- $user_domain_name := eq $user.usage "admin" | ternary "default" "service" }}
6+
{{- $project_domain_name := eq $user.usage "admin" | ternary "default" ( default "service" $user.project_domain_name ) }}
7+
{{- $project_name := eq $user.usage "admin" | ternary "admin" ( default "service" $user.project_name ) }}
8+
---
9+
apiVersion: external-secrets.io/v1
10+
kind: ExternalSecret
11+
metadata:
12+
name: {{ (printf "%s-keystone-%s" $serviceName $user.usage) | quote }}
13+
{{- if $.Values.keystoneServiceUsers.externalLinkAnnotationTemplate }}
14+
annotations:
15+
link.argocd.argoproj.io/external-link: {{ tpl $.Values.keystoneServiceUsers.externalLinkAnnotationTemplate (dict "remoteRef" $user.remoteRef) | quote }}
16+
{{- end }}
17+
spec:
18+
refreshInterval: {{ $.Values.externalSecretsRefreshInterval | default "1h" }}
19+
secretStoreRef:
20+
kind: {{ $.Values.keystoneServiceUsers.secretStore.kind | quote }}
21+
name: {{ $.Values.keystoneServiceUsers.secretStore.name | quote }}
22+
target:
23+
name: {{ (printf "%s-keystone-%s" $serviceName $user.usage) | quote }}
24+
template:
25+
engineVersion: v2
26+
data:
27+
OS_AUTH_URL: {{ $.Values.keystoneUrl | quote }}
28+
OS_DEFAULT_DOMAIN: 'default'
29+
OS_INTERFACE: {{ $.Values.keystoneServiceUsers.keystoneInterface | quote }}
30+
OS_PROJECT_DOMAIN_NAME: {{ $project_domain_name | quote }}
31+
OS_PROJECT_NAME: {{ $project_name | quote }}
32+
OS_USER_DOMAIN_NAME: {{ $user_domain_name | quote }}
33+
OS_USERNAME: {{ `{{ .username }}` | quote }}
34+
OS_PASSWORD: {{ `{{ .password }}` | quote }}
35+
OS_REGION_NAME: {{ $.Values.regionName | quote }}
36+
dataFrom:
37+
- extract:
38+
key: {{ $user.remoteRef | quote }}
39+
{{- end }}
40+
{{- end }}
41+
{{- range $serviceName, $users := .Values.keystoneServiceUsers.services }}
42+
{{- if not (eq $serviceName "keystone") }}
43+
---
44+
apiVersion: external-secrets.io/v1
45+
kind: ExternalSecret
46+
metadata:
47+
name: {{ (printf "%s-ks-etc" $serviceName) | quote }}
48+
spec:
49+
refreshInterval: {{ $.Values.externalSecretsRefreshInterval | default "1h" }}
50+
secretStoreRef:
51+
kind: {{ $.Values.keystoneServiceUsers.secretStore.kind | quote }}
52+
name: {{ $.Values.keystoneServiceUsers.secretStore.name | quote }}
53+
target:
54+
name: {{ (printf "%s-ks-etc" $serviceName) | quote }}
55+
template:
56+
engineVersion: v2
57+
data:
58+
{{ (printf "%s_auth.conf" $serviceName) | quote }}: |
59+
{{- range $_, $user := $users }}
60+
{{- $section := $user.section | default $user.usage }}
61+
{{- $section := eq $section "user" | ternary "keystone_authtoken" $section -}}
62+
{{- $shouldSkip := or (eq $user.usage "test") (eq $user.usage "admin") }}
63+
{{- if not $shouldSkip }}
64+
[{{ $section }}]
65+
username={{ printf "{{ (fromJson .%s).username }}" $user.usage }}
66+
password={{ printf "{{ (fromJson .%s).password }}" $user.usage }}
67+
region_name={{ $.Values.regionName | quote }}
68+
{{- end }}
69+
{{- end }}
70+
data:
71+
{{/* default section name is the usage field */}}
72+
{{/* usage test and admin are special in OpenStack Helm and not added to the config file */}}
73+
{{- range $_, $user := $users -}}
74+
{{- $shouldSkip := or (eq $user.usage "test") (eq $user.usage "admin") -}}
75+
{{- if not $shouldSkip }}
76+
- secretKey: {{ $user.usage }}
77+
remoteRef:
78+
key: {{ $user.remoteRef | quote }}
79+
{{- end }}
80+
{{- end }}
81+
{{- end }}
82+
{{- end }}
83+
{{- end }}

components/openstack/templates/secretstore-openstack.yaml.tpl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type: kubernetes.io/service-account-token
1515
apiVersion: rbac.authorization.k8s.io/v1
1616
kind: Role
1717
metadata:
18-
name: eso-openstack-role
18+
name: eso-openstack
1919
rules:
2020
- apiGroups: [""]
2121
resources:
@@ -28,6 +28,15 @@ rules:
2828
- svc-acct-argoworkflow
2929
- svc-acct-netapp
3030
- cinder-netapp-config
31+
- admin-keystone-password
32+
- cinder-keystone-password
33+
- glance-keystone-password
34+
- ironic-keystone-password
35+
- neutron-keystone-password
36+
- nova-keystone-password
37+
- octavia-keystone-password
38+
- placement-keystone-password
39+
- skyline-keystone-password
3140
- apiGroups:
3241
- authorization.k8s.io
3342
resources:
@@ -38,11 +47,11 @@ rules:
3847
apiVersion: rbac.authorization.k8s.io/v1
3948
kind: RoleBinding
4049
metadata:
41-
name: eso-openstack-rolebinding
50+
name: eso-openstack
4251
roleRef:
4352
apiGroup: rbac.authorization.k8s.io
4453
kind: Role
45-
name: eso-openstack-role
54+
name: eso-openstack
4655
subjects:
4756
- kind: ServiceAccount
4857
name: eso-openstack

components/openstack/values.schema.json

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44
"description": "Schema for OpenStack component values.yaml configuration",
55
"type": "object",
66
"properties": {
7+
"regionName": {
8+
"type": "string",
9+
"description": "OpenStack region that this deployment corresponds to"
10+
},
11+
"keystoneUrl": {
12+
"type": "string",
13+
"default": "http://keystone-api.openstack.svc.cluster.local:5000/v3",
14+
"description": "Keystone API URL for OpenStack authentication"
15+
},
16+
"externalSecretsRefreshInterval": {
17+
"type": "string",
18+
"pattern": "^[0-9]+(s|m|h|d)",
19+
"default": "1h",
20+
"description": "How often External Secrets Operator refreshes each secret"
21+
},
722
"mariadb": {
823
"type": "object",
924
"description": "OpenStack mariadb instance settings",
@@ -104,6 +119,82 @@
104119
},
105120
"additionalProperties": false
106121
},
122+
"keystoneServiceUsers": {
123+
"type": "object",
124+
"description": "OpenStack service users for OpenStack Helm charts",
125+
"properties": {
126+
"enabled": {
127+
"type": "boolean",
128+
"description": "Enables or disables loading OpenStack service users via External Secrets Operator"
129+
},
130+
"secretStore": {
131+
"type": "object",
132+
"description": "External Secrets Operator Secret Store configuration",
133+
"properties": {
134+
"kind": {
135+
"type": "string",
136+
"enum": ["ClusterSecretStore", "SecretStore"],
137+
"description": "Type of secret store - ClusterSecretStore or SecretStore for namespaced"
138+
},
139+
"name": {
140+
"type": "string",
141+
"description": "Name of the ClusterSecretStore or SecretStore to use"
142+
}
143+
},
144+
"required": ["kind", "name"],
145+
"additionalProperties": false
146+
},
147+
"externalLinkAnnotationTemplate": {
148+
"type": "string",
149+
"description": "Optional template for external link annotations on ExternalSecret resources"
150+
},
151+
"keystoneInterface": {
152+
"type": "string",
153+
"default": "internal",
154+
"description": "OpenStack service catalog interface to use"
155+
},
156+
"services": {
157+
"type": "object",
158+
"description": "Service users organized by service name",
159+
"patternProperties": {
160+
"^[a-zA-Z0-9_-]+$": {
161+
"type": "array",
162+
"items": {
163+
"type": "object",
164+
"properties": {
165+
"usage": {
166+
"type": "string",
167+
"description": "Usage identifier for the service user"
168+
},
169+
"remoteRef": {
170+
"type": "string",
171+
"description": "Credential identifier"
172+
},
173+
"section": {
174+
"type": "string",
175+
"description": "Configuration section name"
176+
},
177+
"project_domain_name": {
178+
"type": "string",
179+
"description": "Domain name where this service account will access a project"
180+
},
181+
"project_name": {
182+
"type": "string",
183+
"description": "Project name that this service account will access"
184+
}
185+
},
186+
"required": [
187+
"usage",
188+
"remoteRef"
189+
],
190+
"additionalProperties": false
191+
}
192+
}
193+
}
194+
}
195+
},
196+
"additionalProperties": false
197+
},
107198
"extraObjects": {
108199
"type": "array",
109200
"description": "Array of extra Kubernetes manifests to deploy",
@@ -140,5 +231,6 @@
140231
}
141232
}
142233
},
234+
"required": ["regionName"],
143235
"additionalProperties": false
144236
}

0 commit comments

Comments
 (0)