diff --git a/ansible/playbooks/keystone_bootstrap.yaml b/ansible/playbooks/keystone_bootstrap.yaml index 1d733a658..00dfbd21c 100644 --- a/ansible/playbooks/keystone_bootstrap.yaml +++ b/ansible/playbooks/keystone_bootstrap.yaml @@ -18,13 +18,8 @@ connection: local pre_tasks: - - name: Fail if ENV variables are not set - ansible.builtin.fail: - msg: "Environment variable {{ item }} is not set. Exiting playbook." - when: lookup('env', item) == '' - loop: - - OS_USERNAME - - OS_DEFAULT_DOMAIN + - name: Check OpenStack connectivity + ansible.builtin.import_tasks: ../tasks/check_openstack_auth.yml roles: - role: keystone_bootstrap diff --git a/ansible/playbooks/openstack_network.yaml b/ansible/playbooks/openstack_network.yaml index 8e48d3733..36668f244 100644 --- a/ansible/playbooks/openstack_network.yaml +++ b/ansible/playbooks/openstack_network.yaml @@ -18,12 +18,8 @@ connection: local pre_tasks: - - name: Fail if ENV variables are not set - ansible.builtin.fail: - msg: "Environment variable {{ item }} is not set. Exiting playbook." - when: lookup('env', item) == '' - loop: - - OS_CLOUD + - name: Check OpenStack connectivity + ansible.builtin.import_tasks: ../tasks/check_openstack_auth.yml roles: - role: openstack_network diff --git a/ansible/playbooks/openstack_octavia.yaml b/ansible/playbooks/openstack_octavia.yaml index 34c181a15..833857be1 100644 --- a/ansible/playbooks/openstack_octavia.yaml +++ b/ansible/playbooks/openstack_octavia.yaml @@ -18,12 +18,8 @@ connection: local pre_tasks: - - name: Fail if ENV variables are not set - ansible.builtin.fail: - msg: "Environment variable {{ item }} is not set. Exiting playbook." - when: lookup('env', item) == '' - loop: - - OS_CLOUD + - name: Check OpenStack connectivity + ansible.builtin.import_tasks: ../tasks/check_openstack_auth.yml roles: - role: openstack_octavia diff --git a/ansible/tasks/check_openstack_auth.yml b/ansible/tasks/check_openstack_auth.yml new file mode 100644 index 000000000..a40a1561e --- /dev/null +++ b/ansible/tasks/check_openstack_auth.yml @@ -0,0 +1,12 @@ +- name: Authenticate to Keystone + openstack.cloud.auth: + timeout: 20 + register: auth + +- name: Assert OpenStack authentication succeeded + ansible.builtin.assert: + that: + - auth.auth_token is defined + - auth.auth_token | length > 0 + success_msg: "OpenStack authentication successful" + fail_msg: "OpenStack authentication failed." diff --git a/components/nautobot/values.yaml b/components/nautobot/values.yaml index 11be1cc72..fecc4dc96 100644 --- a/components/nautobot/values.yaml +++ b/components/nautobot/values.yaml @@ -116,9 +116,6 @@ extraObjects: "helm.sh/hook-weight": "1" "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded spec: - ttlSecondsAfterFinished: 300 - # allow the ansible container to run for 20 minutes - activeDeadlineSeconds: 1200 backoffLimit: 1 template: spec: @@ -135,10 +132,10 @@ extraObjects: command: ["ansible-runner", "run", "/runner", "--playbook", "nautobot-initial-setup.yaml"] resources: requests: - cpu: "100m" + cpu: "1000m" memory: "512Mi" limits: - cpu: "500m" + cpu: "1000m" memory: "512Mi" securityContext: allowPrivilegeEscalation: false diff --git a/components/neutron/kustomization.yaml b/components/neutron/kustomization.yaml index 3491a9047..7f5158890 100644 --- a/components/neutron/kustomization.yaml +++ b/components/neutron/kustomization.yaml @@ -5,7 +5,7 @@ kind: Kustomization resources: - neutron-mariadb-db.yaml - neutron-rabbitmq-queue.yaml - - neutron-nautobot.yaml + - neutron-post-deployment-job.yaml # less than ideal addition but necessary so that we can have the neutron.conf.d loading # working due to the way the chart hardcodes the config-file parameter which then # takes precedence over the directory diff --git a/components/neutron/neutron-nautobot.yaml b/components/neutron/neutron-nautobot.yaml deleted file mode 100644 index c389e189d..000000000 --- a/components/neutron/neutron-nautobot.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- -apiVersion: external-secrets.io/v1 -kind: ExternalSecret -metadata: - name: neutron-nautobot - namespace: openstack -spec: - refreshInterval: 1h - secretStoreRef: - kind: ClusterSecretStore - name: nautobot - target: - name: neutron-nautobot - creationPolicy: Owner - deletionPolicy: Delete - template: - engineVersion: v2 - data: - ml2_understack.conf: | - [ml2_understack] - nb_url = http://nautobot-default.nautobot.svc.cluster.local - nb_token = {{ .token }} - data: - - secretKey: token - remoteRef: - key: nautobot-superuser - property: apitoken diff --git a/components/neutron/neutron-post-deployment-job.yaml b/components/neutron/neutron-post-deployment-job.yaml new file mode 100644 index 000000000..64f4c7ca0 --- /dev/null +++ b/components/neutron/neutron-post-deployment-job.yaml @@ -0,0 +1,64 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: neutron-post-deployment-job + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceeded +spec: + backoffLimit: 2 + template: + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 + seccompProfile: + type: RuntimeDefault + containers: + - name: ansible + image: ghcr.io/rackerlabs/understack/ansible:latest + imagePullPolicy: Always + command: ["ansible-runner", "run", "/runner", "--playbook", "openstack_network.yaml"] + resources: + requests: + cpu: "1000m" + memory: "512Mi" + limits: + cpu: "1000m" + memory: "512Mi" + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + env: + - name: OS_CLOUD + value: understack + volumeMounts: + - name: ansible-inventory + mountPath: /runner/inventory/ + - name: ansible-group-vars + mountPath: /runner/inventory/group_vars/ + - name: infrasetup + mountPath: /etc/openstack + readOnly: true + volumes: + - name: runner-data + emptyDir: {} + - name: ansible-inventory + configMap: + name: ansible-inventory + - name: ansible-group-vars + configMap: + name: ansible-group-vars + - name: infrasetup + secret: + secretName: infrasetup + items: + - key: clouds.yaml + path: clouds.yaml + restartPolicy: OnFailure diff --git a/components/octavia/octavia-post-deployment-job.yaml b/components/octavia/octavia-post-deployment-job.yaml index 91c45bd74..a414c82b0 100644 --- a/components/octavia/octavia-post-deployment-job.yaml +++ b/components/octavia/octavia-post-deployment-job.yaml @@ -3,18 +3,38 @@ apiVersion: batch/v1 kind: Job metadata: name: octavia-post-deployment-job - generateName: octavia-post-deployment-job- annotations: argocd.argoproj.io/hook: PostSync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation + argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceeded spec: + backoffLimit: 2 template: spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 + seccompProfile: + type: RuntimeDefault containers: - - name: octavia-post-deploy + - name: ansible image: ghcr.io/rackerlabs/understack/ansible:latest imagePullPolicy: Always command: ["ansible-runner", "run", "/runner", "-vvv", "--playbook", "openstack_octavia.yaml"] + resources: + requests: + cpu: "1000m" + memory: "512Mi" + limits: + cpu: "1000m" + memory: "512Mi" + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false env: - name: OS_CLOUD value: understack @@ -27,7 +47,7 @@ spec: subPath: inventory.yaml - name: ansible-group-vars mountPath: /runner/inventory/group_vars/ - - name: openstack-svc-acct + - name: infrasetup mountPath: /etc/openstack readOnly: true volumes: @@ -42,7 +62,10 @@ spec: - name: ansible-group-vars configMap: name: ansible-group-vars - - name: openstack-svc-acct + - name: infrasetup secret: - secretName: openstack-svc-acct + secretName: infrasetup + items: + - key: clouds.yaml + path: clouds.yaml restartPolicy: OnFailure diff --git a/components/openstack/templates/automation-infrasetup.yaml.tpl b/components/openstack/templates/automation-infrasetup.yaml.tpl new file mode 100644 index 000000000..d43794d14 --- /dev/null +++ b/components/openstack/templates/automation-infrasetup.yaml.tpl @@ -0,0 +1,46 @@ +--- +apiVersion: generators.external-secrets.io/v1alpha1 +kind: Password +metadata: + name: "infrasetup-{{ .Values.regionName }}" +spec: + length: 32 + digits: 6 + symbols: 6 +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: "infrasetup-{{ .Values.regionName }}" +spec: + refreshInterval: 20160m + target: + name: infrasetup + template: + engineVersion: v2 + type: Opaque + metadata: + labels: + understack.rackspace.com/keystone-role: infra-readwrite + understack.rackspace.com/keystone-user: "infrasetup-{{ .Values.regionName }}" + data: + password: "{{ `{{ .password }}` }}" + clouds.yaml: | + clouds: + understack: + auth: + auth_url: "{{ .Values.keystoneUrl }}" + user_domain_name: "service" + username: "infrasetup-{{ .Values.regionName }}" + password: "{{ `{{ .password }}` }}" + project_domain_name: "infra" + project_name: "baremetal" + region_name: "{{ .Values.regionName }}" + interface: "public" + identity_api_version: 3 + dataFrom: + - sourceRef: + generatorRef: + apiVersion: generators.external-secrets.io/v1alpha1 + kind: Password + name: "infrasetup-{{ .Values.regionName }}" diff --git a/components/site-workflows/eventsources/eventsource-k8s-openstack-neutron.yaml b/components/site-workflows/eventsources/eventsource-k8s-openstack-neutron.yaml deleted file mode 100644 index 88b767f7b..000000000 --- a/components/site-workflows/eventsources/eventsource-k8s-openstack-neutron.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: argoproj.io/v1alpha1 -kind: EventSource -metadata: - name: k8s-openstack-neutron - namespace: openstack -spec: - template: - serviceAccountName: k8s-openstack-events - # Kubernetes resource event sources - resource: - neutron-deployment: - # monitor deployment resources under openstack namespace - namespace: openstack - resource: deployments - group: apps - version: v1 - # Event types to listen for (e.g., ADD, UPDATE, DELETE). Here we want only when deployment is created. - eventTypes: - - ADD - filter: - # filter based these labels to match neutron-server deployment - labels: - - key: application - value: neutron - - key: component - value: server diff --git a/components/site-workflows/eventsources/eventsource-k8s-openstack-secrets.yaml b/components/site-workflows/eventsources/eventsource-k8s-openstack-secrets.yaml index b75490465..621874441 100644 --- a/components/site-workflows/eventsources/eventsource-k8s-openstack-secrets.yaml +++ b/components/site-workflows/eventsources/eventsource-k8s-openstack-secrets.yaml @@ -8,7 +8,7 @@ spec: serviceAccountName: k8s-openstack-events-secrets # Kubernetes resource event sources resource: - keystone-integration-reader-add: + keystone-automation-user-upsert: # monitor deployment resources under openstack namespace namespace: openstack group: "" @@ -24,7 +24,7 @@ spec: operation: exists - key: understack.rackspace.com/keystone-user operation: exists - keystone-integration-reader-delete: + keystone-automation-user-delete: # monitor deployment resources under openstack namespace namespace: openstack group: "" diff --git a/components/site-workflows/kustomization.yaml b/components/site-workflows/kustomization.yaml index 2d23b5606..f3515509b 100644 --- a/components/site-workflows/kustomization.yaml +++ b/components/site-workflows/kustomization.yaml @@ -10,21 +10,17 @@ resources: - eventsources/rabbitmq-user-argo-ironic.yaml - eventsources/rabbitmq-user-argo-keystone.yaml - eventsources/rabbitmq-user-argo-neutron.yaml - - eventsources/eventsource-k8s-openstack-neutron.yaml - eventsources/eventsource-k8s-openstack-secrets.yaml - serviceaccounts/serviceaccount-sensor-submit-workflow.yaml - - serviceaccounts/serviceaccount-k8s-openstack-events.yaml - serviceaccounts/serviceaccount-k8s-openstack-events-secrets.yaml - sensors/sensor-ironic-node-update.yaml - sensors/sensor-keystone-event-project.yaml - sensors/sensor-keystone-oslo-event.yaml - - sensors/sensor-k8s-neutron-deployment.yaml - - sensors/sensor-keystone-integration-reader-add.yaml - - sensors/sensor-keystone-integration-reader-rm.yaml + - sensors/sensor-keystone-automation-user-upsert.yaml + - sensors/sensor-keystone-automation-user-delete.yaml - sensors/sensor-neutron-event-network-segment-range.yaml - sensors/sensor-neutron-olso-event.yaml - sensors/sensor-ironic-reclean.yaml - sensors/sensor-ironic-node-port.yaml - sensors/sensor-ironic-oslo-event.yaml - secrets/nautobot-token.yaml - - secrets/openstack-svc-acct.yaml diff --git a/components/site-workflows/secrets/openstack-svc-acct.yaml b/components/site-workflows/secrets/openstack-svc-acct.yaml deleted file mode 100644 index 32c19bca3..000000000 --- a/components/site-workflows/secrets/openstack-svc-acct.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: external-secrets.io/v1 -kind: ExternalSecret -metadata: - name: openstack-svc-acct -spec: - refreshInterval: 1h - secretStoreRef: - kind: ClusterSecretStore - name: openstack - target: - name: openstack-svc-acct - template: - engineVersion: v2 - data: - clouds.yaml: | - clouds: - understack: - auth_url: http://keystone-api.openstack.svc.cluster.local:5000/v3 - user_domain_name: {{ .user_domain }} - username: {{ .username }} - password: {{ .password }} - project_domain_name: infra - project_name: baremetal - dataFrom: - - extract: - key: svc-acct-argoworkflow - # necessary to avoid argoproj/argo-cd#13004 - conversionStrategy: Default - decodingStrategy: None - metadataPolicy: None diff --git a/components/site-workflows/sensors/sensor-k8s-neutron-deployment.yaml b/components/site-workflows/sensors/sensor-k8s-neutron-deployment.yaml deleted file mode 100644 index fadd0b788..000000000 --- a/components/site-workflows/sensors/sensor-k8s-neutron-deployment.yaml +++ /dev/null @@ -1,58 +0,0 @@ ---- -apiVersion: argoproj.io/v1alpha1 -kind: Sensor -metadata: - name: neutron-deployment - namespace: openstack -spec: - template: - serviceAccountName: k8s-openstack-events - # events the Sensor listens for - dependencies: - - eventName: neutron-deployment - eventSourceName: k8s-openstack-neutron - name: openstack-neutron-server-deployment - # actions executed when dependencies are satisfied (StandardK8STrigger designed to create or update a generic Kubernetes resource.) - triggers: - - template: - name: create-provisioning-network - k8s: - operation: create - source: - resource: - apiVersion: batch/v1 - kind: Job - metadata: - generateName: create-provision-network - spec: - template: - spec: - containers: - - name: create-provisioning-network - image: ghcr.io/rackerlabs/understack/ansible:latest - imagePullPolicy: Always - command: ["ansible-runner", "run", "/runner", "--playbook", "openstack_network.yaml"] - env: - - name: OS_CLOUD - value: understack - volumeMounts: - - name: ansible-inventory - mountPath: /runner/inventory/ - - name: ansible-group-vars - mountPath: /runner/inventory/group_vars/ - - name: openstack-svc-acct - mountPath: /etc/openstack - readOnly: true - volumes: - - name: runner-data - emptyDir: {} - - name: ansible-inventory - configMap: - name: ansible-inventory - - name: ansible-group-vars - configMap: - name: ansible-group-vars - - name: openstack-svc-acct - secret: - secretName: openstack-svc-acct - restartPolicy: OnFailure diff --git a/components/site-workflows/sensors/sensor-keystone-integration-reader-rm.yaml b/components/site-workflows/sensors/sensor-keystone-automation-user-delete.yaml similarity index 90% rename from components/site-workflows/sensors/sensor-keystone-integration-reader-rm.yaml rename to components/site-workflows/sensors/sensor-keystone-automation-user-delete.yaml index b7fc84c5f..e50dba5f3 100644 --- a/components/site-workflows/sensors/sensor-keystone-integration-reader-rm.yaml +++ b/components/site-workflows/sensors/sensor-keystone-automation-user-delete.yaml @@ -2,7 +2,7 @@ apiVersion: argoproj.io/v1alpha1 kind: Sensor metadata: - name: keystone-integration-reader-rm + name: keystone-automation-user-delete namespace: openstack spec: template: @@ -10,12 +10,12 @@ spec: # events the Sensor listens for dependencies: - name: secret-dep - eventName: keystone-integration-reader-delete + eventName: keystone-automation-user-delete eventSourceName: k8s-openstack-secrets # actions executed when dependencies are satisfied (StandardK8STrigger designed to create or update a generic Kubernetes resource.) triggers: - template: - name: keystone-user-delete + name: keystone-automation-user-delete k8s: operation: create source: @@ -23,14 +23,14 @@ spec: apiVersion: batch/v1 kind: Job metadata: - generateName: keystone-integration-reader-rm- + generateName: keystone-automation-user-delete- spec: ttlSecondsAfterFinished: 600 backoffLimit: 3 template: spec: containers: - - name: keystone-user-delete + - name: openstackcli image: quay.io/airshipit/heat:2025.1-ubuntu_jammy command: ["sh", "-c"] args: diff --git a/components/site-workflows/sensors/sensor-keystone-integration-reader-add.yaml b/components/site-workflows/sensors/sensor-keystone-automation-user-upsert.yaml similarity index 88% rename from components/site-workflows/sensors/sensor-keystone-integration-reader-add.yaml rename to components/site-workflows/sensors/sensor-keystone-automation-user-upsert.yaml index 33d649311..626e4e696 100644 --- a/components/site-workflows/sensors/sensor-keystone-integration-reader-add.yaml +++ b/components/site-workflows/sensors/sensor-keystone-automation-user-upsert.yaml @@ -2,7 +2,7 @@ apiVersion: argoproj.io/v1alpha1 kind: Sensor metadata: - name: keystone-integration-reader-add + name: keystone-automation-user-upsert namespace: openstack spec: template: @@ -10,12 +10,12 @@ spec: # events the Sensor listens for dependencies: - name: secret-dep - eventName: keystone-integration-reader-add + eventName: keystone-automation-user-upsert eventSourceName: k8s-openstack-secrets # actions executed when dependencies are satisfied (StandardK8STrigger designed to create or update a generic Kubernetes resource.) triggers: - template: - name: keystone-user-create-update + name: keystone-automation-user-upsert k8s: operation: create source: @@ -23,14 +23,14 @@ spec: apiVersion: batch/v1 kind: Job metadata: - generateName: keystone-integration-reader-add- + generateName: keystone-automation-user-upsert- spec: ttlSecondsAfterFinished: 600 backoffLimit: 3 template: spec: containers: - - name: keystone-user-create-update + - name: openstackcli image: quay.io/airshipit/heat:2025.1-ubuntu_jammy command: ["sh", "-c"] args: @@ -40,12 +40,16 @@ spec: SVC_ROLES=$(python -c "import json,os; print(json.loads(os.environ.get('LABELS') or '{}').get('understack.rackspace.com/keystone-role',''))") SVC_USER=$(python -c "import json,os; print(json.loads(os.environ.get('LABELS') or '{}').get('understack.rackspace.com/keystone-user',''))") SVC_USER=${SVC_USER:-$SECRET_NAME} - PROJ_ID=$(openstack project create --or-show --domain service integration -f value -c id) + PROJ_ID=$(openstack project create --or-show --domain service automation -f value -c id) SVC_ID=$(openstack user create --or-show --domain service --project "${PROJ_ID}" --description "${SECRET_NAME}" "${SVC_USER}" -f value -c id) openstack user set --description "${SECRET_NAME}" --project "${PROJ_ID}" "${SVC_ID}" set +x svc_pass=$(cat /tmp/user-create/password) - openstack user set --password "${svc_pass}" "${SVC_ID}" + if [ -z "${svc_pass}" ]; then + echo "Empty password supplied, skipping setting the password" + else + openstack user set --password "${svc_pass}" "${SVC_ID}" + fi set -x openstack role add --user "${SVC_ID}" --project "${PROJ_ID}" reader IFS=',' diff --git a/components/site-workflows/serviceaccounts/serviceaccount-k8s-openstack-events.yaml b/components/site-workflows/serviceaccounts/serviceaccount-k8s-openstack-events.yaml deleted file mode 100644 index 907202faf..000000000 --- a/components/site-workflows/serviceaccounts/serviceaccount-k8s-openstack-events.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - namespace: openstack - name: k8s-openstack-events - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - namespace: openstack - name: k8s-openstack-events-role -rules: - - apiGroups: - - "" - - apps - - batch - resources: - - pods - - deployments - - jobs - verbs: - - '*' - ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - namespace: openstack - name: k8s-openstack-events-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: k8s-openstack-events-role -subjects: - - kind: ServiceAccount - name: k8s-openstack-events - namespace: openstack diff --git a/docs/deploy-guide/openstack-svc-users.md b/docs/deploy-guide/openstack-automation-users.md similarity index 90% rename from docs/deploy-guide/openstack-svc-users.md rename to docs/deploy-guide/openstack-automation-users.md index e7adf62bc..2fc832383 100644 --- a/docs/deploy-guide/openstack-svc-users.md +++ b/docs/deploy-guide/openstack-automation-users.md @@ -1,6 +1,6 @@ -# OpenStack Service Users +# OpenStack Automation Users -Should you need to create service accounts in OpenStack you can do so +Should you need to an account in OpenStack for automation, you can do so by creating a Kubernetes Secret in the `openstack` namespace with the following labels: diff --git a/mkdocs.yml b/mkdocs.yml index fd3e22768..f06e88383 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -138,7 +138,7 @@ nav: - deploy-guide/config-dex.md - deploy-guide/config-openstack.md - deploy-guide/secrets-eso-setup.md - - deploy-guide/openstack-svc-users.md + - deploy-guide/openstack-automation-users.md - deploy-guide/nautobot-secrets.md - deploy-guide/auth.md - deploy-guide/config-argo-workflows.md