Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions ansible/roles/keystone_bootstrap/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,29 @@ keystone_bootstrap_groups:
# role: member
# - project: shared-services
# role: reader

# domain in which k8s service account groups are created
keystone_bootstrap_k8s_group_domain: service

# k8s identity providers; override with your cluster issuers
keystone_k8s_identity:
providers: []

# k8s service account groups and their project role assignments
# Each group can have project_roles with an optional domain to scope the project lookup
keystone_bootstrap_k8s_groups:
- name: k8s-serviceaccounts
desc: 'Kubernetes Service Accounts'
project_roles:
- project: service
domain: service
role: admin
- project: service
domain: service
role: service
- project: baremetal
domain: infra
role: admin
- project: baremetal
domain: infra
role: service
54 changes: 54 additions & 0 deletions ansible/roles/keystone_bootstrap/tasks/k8s.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
# Copyright (c) 2026 Rackspace Technology, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Create k8s mapping
openstack.cloud.federation_mapping:
name: k8s-mapping
rules:
- local:
- user:
name: '{0}'
group:
domain:
name: service
name: k8s-serviceaccounts
remote:
- type: HTTP_OIDC_SUB

- name: Create k8s identity providers
openstack.cloud.federation_idp:
name: "{{ item.name }}"
is_enabled: true
remote_ids:
- "{{ item.issuer }}"
loop: "{{ keystone_k8s_identity.providers }}"

- name: Create k8s openid protocols
openstack.cloud.keystone_federation_protocol:
name: openid
idp: "{{ item.name }}"
mapping: k8s-mapping
loop: "{{ keystone_k8s_identity.providers }}"

- name: Get k8s group domain info
openstack.cloud.identity_domain_info:
name: "{{ keystone_bootstrap_k8s_group_domain }}"
register: _k8s_group_domain

- name: Create k8s service account group mappings
ansible.builtin.include_tasks: k8s_group.yml
loop: "{{ keystone_bootstrap_k8s_groups }}"
loop_control:
loop_var: group_item
34 changes: 34 additions & 0 deletions ansible/roles/keystone_bootstrap/tasks/k8s_group.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
# Copyright (c) 2026 Rackspace Technology, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Create k8s group
openstack.cloud.identity_group:
name: "{{ group_item.name }}"
domain_id: "{{ _k8s_group_domain.domains[0].id }}"
description: "{{ group_item.desc }}"
state: present
register: _k8s_group

- name: Assign role to k8s group for project
openstack.cloud.role_assignment:
group: "{{ _k8s_group.group.id }}"
project: "{{ role_item.project }}"
project_domain: "{{ role_item.domain | default(omit) }}"
role: "{{ role_item.role }}"
state: present
loop: "{{ group_item.project_roles | default([]) }}"
loop_control:
loop_var: role_item
when: dont_set_roles is not defined
3 changes: 3 additions & 0 deletions ansible/roles/keystone_bootstrap/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@
- name: Define SSO
ansible.builtin.include_tasks: sso.yml

- name: Define k8s service account groups
ansible.builtin.include_tasks: k8s.yml

- name: Define misc keystone
ansible.builtin.include_tasks: misc.yml
30 changes: 30 additions & 0 deletions charts/argocd-understack/templates/application-oidc-rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{{- if or (eq (include "understack.isEnabled" (list $.Values.global "oidc_rbac")) "true") (eq (include "understack.isEnabled" (list $.Values.site "oidc_rbac")) "true") }}
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ printf "%s-%s" $.Release.Name "oidc-rbac" }}
finalizers:
- resources-finalizer.argocd.argoproj.io
annotations:
argocd.argoproj.io/compare-options: ServerSideDiff=true,IncludeMutationWebhook=true
{{- include "understack.appLabelsBlock" $ | nindent 2 }}
spec:
destination:
namespace: kube-system
server: {{ $.Values.cluster_server }}
project: understack-infra
sources:
- path: components/oidc-rbac
ref: understack
repoURL: {{ include "understack.understack_url" $ }}
targetRevision: {{ include "understack.understack_ref" $ }}
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- ServerSideApply=true
- RespectIgnoreDifferences=true
- ApplyOutOfSyncOnly=true
{{- end }}
12 changes: 12 additions & 0 deletions charts/argocd-understack/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ global:
# @default -- false
enabled: false

# -- OIDC RBAC (ClusterRoleBindings for OIDC service account issuer discovery)
oidc_rbac:
# -- Enable/disable deploying OIDC RBAC
# @default -- false
enabled: false

# -- OpenEBS
openebs:
# -- Enable/disable deploying OpenEBS
Expand Down Expand Up @@ -505,6 +511,12 @@ site:
# @default -- false
enabled: false

# -- OIDC RBAC (ClusterRoleBindings for OIDC service account issuer discovery)
oidc_rbac:
# -- Enable/disable deploying OIDC RBAC
# @default -- false
enabled: false

# -- OpenEBS
openebs:
# -- Enable/disable deploying OpenEBS
Expand Down
126 changes: 63 additions & 63 deletions components/images-openstack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ images:
tags:
# these are common across all these OpenStack Helm installations
bootstrap: "ghcr.io/rackerlabs/understack/ansible:latest"
db_init: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
db_drop: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
ks_user: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
ks_service: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
ks_endpoints: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
db_init: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
db_drop: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
ks_user: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
ks_service: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
ks_endpoints: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"

# keystone
keystone_api: "ghcr.io/rackerlabs/understack/keystone:2025.2"
keystone_credential_rotate: "ghcr.io/rackerlabs/understack/keystone:2025.2"
keystone_credential_setup: "ghcr.io/rackerlabs/understack/keystone:2025.2"
keystone_db_sync: "ghcr.io/rackerlabs/understack/keystone:2025.2"
keystone_domain_manage: "ghcr.io/rackerlabs/understack/keystone:2025.2"
keystone_fernet_rotate: "ghcr.io/rackerlabs/understack/keystone:2025.2"
keystone_fernet_setup: "ghcr.io/rackerlabs/understack/keystone:2025.2"
keystone_api: "ghcr.io/rackerlabs/understack/keystone:pr-1876"
keystone_credential_rotate: "ghcr.io/rackerlabs/understack/keystone:pr-1876"
keystone_credential_setup: "ghcr.io/rackerlabs/understack/keystone:pr-1876"
keystone_db_sync: "ghcr.io/rackerlabs/understack/keystone:pr-1876"
keystone_domain_manage: "ghcr.io/rackerlabs/understack/keystone:pr-1876"
keystone_fernet_rotate: "ghcr.io/rackerlabs/understack/keystone:pr-1876"
keystone_fernet_setup: "ghcr.io/rackerlabs/understack/keystone:pr-1876"

# ironic
ironic_api: "ghcr.io/rackerlabs/understack/ironic:2026.1"
Expand All @@ -29,43 +29,43 @@ images:
ironic_pxe_http: "docker.io/nginx:1.29.8"
ironic_db_sync: "ghcr.io/rackerlabs/understack/ironic:2026.1"
# these want curl which apparently is in the openstack-client image
ironic_manage_cleaning_network: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
ironic_retrive_cleaning_network: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
ironic_retrive_swift_config: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
ironic_manage_cleaning_network: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
ironic_retrive_cleaning_network: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
ironic_retrive_swift_config: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"

# neutron
neutron_db_sync: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_dhcp: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_l3: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_l2gw: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_linuxbridge_agent: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_metadata: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_ovn_metadata: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_openvswitch_agent: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_server: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_rpc_server: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_bagpipe_bgp: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_netns_cleanup_cron: "ghcr.io/rackerlabs/understack/neutron:2025.2"
neutron_db_sync: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_dhcp: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_l3: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_l2gw: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_linuxbridge_agent: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_metadata: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_ovn_metadata: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_openvswitch_agent: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_server: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_rpc_server: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_bagpipe_bgp: "ghcr.io/rackerlabs/understack/neutron:pr-1876"
neutron_netns_cleanup_cron: "ghcr.io/rackerlabs/understack/neutron:pr-1876"

# nova
nova_api: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_cell_setup: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_cell_setup_init: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
nova_compute: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_compute_ironic: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_compute_ssh: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_conductor: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_db_sync: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_novncproxy: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_novncproxy_assets: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_scheduler: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_spiceproxy: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_spiceproxy_assets: "ghcr.io/rackerlabs/understack/nova:2025.2"
nova_api: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_cell_setup: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_cell_setup_init: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
nova_compute: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_compute_ironic: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_compute_ssh: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_conductor: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_db_sync: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_novncproxy: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_novncproxy_assets: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_scheduler: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_spiceproxy: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_spiceproxy_assets: "ghcr.io/rackerlabs/understack/nova:pr-1876"
nova_service_cleaner: "docker.io/openstackhelm/ceph-config-helper:latest-ubuntu_jammy"

# placement
placement: "ghcr.io/rackerlabs/understack/placement:2025.2"
placement_db_sync: "ghcr.io/rackerlabs/understack/placement:2025.2"
placement: "ghcr.io/rackerlabs/understack/placement:pr-1876"
placement_db_sync: "ghcr.io/rackerlabs/understack/placement:pr-1876"

# openvswitch
openvswitch_db_server: "docker.io/openstackhelm/openvswitch:ubuntu_jammy-dpdk-20250127"
Expand All @@ -78,36 +78,36 @@ images:
ovn_controller: "docker.io/openstackhelm/ovn:ubuntu_jammy-20250111"

# horizon
horizon: "ghcr.io/rackerlabs/understack/horizon:2025.2"
horizon_db_sync: "ghcr.io/rackerlabs/understack/horizon:2025.2"
horizon: "ghcr.io/rackerlabs/understack/horizon:pr-1876"
horizon_db_sync: "ghcr.io/rackerlabs/understack/horizon:pr-1876"

# glance
glance_api: "ghcr.io/rackerlabs/understack/glance:2025.2"
glance_db_sync: "ghcr.io/rackerlabs/understack/glance:2025.2"
glance_metadefs_load: "ghcr.io/rackerlabs/understack/glance:2025.2"
glance_api: "ghcr.io/rackerlabs/understack/glance:pr-1876"
glance_db_sync: "ghcr.io/rackerlabs/understack/glance:pr-1876"
glance_metadefs_load: "ghcr.io/rackerlabs/understack/glance:pr-1876"
glance_storage_init: "docker.io/openstackhelm/ceph-config-helper:latest-ubuntu_jammy"

# skyline
skyline: "ghcr.io/rackerlabs/understack/skyline:2025.2"
skyline_db_sync: "ghcr.io/rackerlabs/understack/skyline:2025.2"
skyline_nginx: "ghcr.io/rackerlabs/understack/skyline:2025.2"
skyline: "ghcr.io/rackerlabs/understack/skyline:pr-1876"
skyline_db_sync: "ghcr.io/rackerlabs/understack/skyline:pr-1876"
skyline_nginx: "ghcr.io/rackerlabs/understack/skyline:pr-1876"

# cinder
cinder_api: "ghcr.io/rackerlabs/understack/cinder:2025.2"
cinder_db_sync: "ghcr.io/rackerlabs/understack/cinder:2025.2"
cinder_scheduler: "ghcr.io/rackerlabs/understack/cinder:2025.2"
cinder_volume: "ghcr.io/rackerlabs/understack/cinder:2025.2"
cinder_volume_usage_audit: "ghcr.io/rackerlabs/understack/cinder:2025.2"
cinder_db_purge: "ghcr.io/rackerlabs/understack/cinder:2025.2"
cinder_backup: "ghcr.io/rackerlabs/understack/cinder:2025.2"
cinder_api: "ghcr.io/rackerlabs/understack/cinder:pr-1876"
cinder_db_sync: "ghcr.io/rackerlabs/understack/cinder:pr-1876"
cinder_scheduler: "ghcr.io/rackerlabs/understack/cinder:pr-1876"
cinder_volume: "ghcr.io/rackerlabs/understack/cinder:pr-1876"
cinder_volume_usage_audit: "ghcr.io/rackerlabs/understack/cinder:pr-1876"
cinder_db_purge: "ghcr.io/rackerlabs/understack/cinder:pr-1876"
cinder_backup: "ghcr.io/rackerlabs/understack/cinder:pr-1876"
cinder_storage_init: "docker.io/openstackhelm/ceph-config-helper:latest-ubuntu_jammy"
cinder_backup_storage_init: "docker.io/openstackhelm/ceph-config-helper:latest-ubuntu_jammy"

# octavia
octavia_api: "ghcr.io/rackerlabs/understack/octavia:2025.2"
octavia_db_sync: "ghcr.io/rackerlabs/understack/octavia:2025.2"
octavia_worker: "ghcr.io/rackerlabs/understack/octavia:2025.2"
octavia_housekeeping: "ghcr.io/rackerlabs/understack/octavia:2025.2"
octavia_health_manager: "ghcr.io/rackerlabs/understack/octavia:2025.2"
octavia_health_manager_init: "ghcr.io/rackerlabs/understack/openstack-client:2025.2"
octavia_api: "ghcr.io/rackerlabs/understack/octavia:pr-1876"
octavia_db_sync: "ghcr.io/rackerlabs/understack/octavia:pr-1876"
octavia_worker: "ghcr.io/rackerlabs/understack/octavia:pr-1876"
octavia_housekeeping: "ghcr.io/rackerlabs/understack/octavia:pr-1876"
octavia_health_manager: "ghcr.io/rackerlabs/understack/octavia:pr-1876"
octavia_health_manager_init: "ghcr.io/rackerlabs/understack/openstack-client:pr-1876"
...
15 changes: 15 additions & 0 deletions components/keystone/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,19 @@ pod:
- name: oidc-secret
mountPath: /etc/oidc-secret
readOnly: true
- name: oidc-metadata
readOnly: true
volumes:
- name: keystone-sso
secret:
secretName: keystone-sso
- name: oidc-secret
secret:
secretName: sso-passphrase
- name: oidc-metadata
configMap:
name: keystone-oidc-metadata
defaultMode: 0555
keystone_bootstrap:
keystone_bootstrap:
volumeMounts:
Expand Down Expand Up @@ -402,3 +408,12 @@ annotations:
# relies on services to be up so it can remain post
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
argocd.argoproj.io/sync-options: Force=true

extraObjects:
- apiVersion: v1
kind: ConfigMap
metadata:
name: keystone-oidc-metadata
namespace: openstack
data:
# Define your OIDC providers metadata in deploy repo
5 changes: 5 additions & 0 deletions components/oidc-rbac/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- oidc-reviewer.yaml
Loading
Loading