From d1e27389b12ddedafc58466f9979a06844c3c804 Mon Sep 17 00:00:00 2001 From: Jonathan Rosser Date: Wed, 8 Mar 2023 08:39:25 +0000 Subject: [PATCH] Deploy step-ca when 'stepca' is part of the deployment scenario. There is currently no CI testing of support for Letsencrypt/ACME in Openstack-Ansible. Adding testing first requires a suitable CA and we cannot use the LE staging environment as it cannot be guaranteed to have connectivity, and there is also no reasonable DNS entry that will work universally for all AIO/CI builds. This patch deploys Step-CA locally on the deployment/AIO node and configures a sufficiently functional ACME API endpoint and root CA. Change-Id: Ib0770ed20c12111dacc6bb63436d0b58d108b853 --- tests/roles/bootstrap-host/defaults/main.yml | 20 +++ .../files/step_ca_x509_template.tpl | 15 +++ tests/roles/bootstrap-host/tasks/main.yml | 13 ++ .../bootstrap-host/tasks/prepare_step_ca.yml | 119 ++++++++++++++++++ .../templates/step-ca.service.j2 | 50 ++++++++ tests/roles/bootstrap-host/vars/debian.yml | 4 + tests/roles/bootstrap-host/vars/redhat.yml | 4 + 7 files changed, 225 insertions(+) create mode 100644 tests/roles/bootstrap-host/files/step_ca_x509_template.tpl create mode 100644 tests/roles/bootstrap-host/tasks/prepare_step_ca.yml create mode 100644 tests/roles/bootstrap-host/templates/step-ca.service.j2 diff --git a/tests/roles/bootstrap-host/defaults/main.yml b/tests/roles/bootstrap-host/defaults/main.yml index d7b38c9a7f..96203c7143 100644 --- a/tests/roles/bootstrap-host/defaults/main.yml +++ b/tests/roles/bootstrap-host/defaults/main.yml @@ -199,3 +199,23 @@ bootstrap_host_data_disk2_path: '/var/lib/lxc' # Set the install method for the deployment. Options are ['source', 'distro'] bootstrap_host_install_method: "{{ lookup('env', 'INSTALL_METHOD') | default('source', true) }}" + +# step-ca +step_ca_user: step +step_ca_group: step +step_ca_config_dir: "/etc/step-ca" +step_ca_binary: /usr/bin/step-ca + +# CA Info +step_ca_name: "My Certificate Authority" # Name used in a self generated intermediate +step_ca_dns_name: + - '127.0.0.1' +step_ca_listen_address: ":8889" # server bind address/port + +## TLS Cert Info +step_ca_cert_expiry: "48" # default number of hours till expiry +step_ca_cert_org_unit: "My Team" # Organisational Unit Name in Cert +step_ca_cert_organisation: "My Organisation" # Organisation Name in Cert +step_ca_cert_country: "My Country" # Country Name in Cert + +step_ca_intermediate_password: "changeme" diff --git a/tests/roles/bootstrap-host/files/step_ca_x509_template.tpl b/tests/roles/bootstrap-host/files/step_ca_x509_template.tpl new file mode 100644 index 0000000000..99505f971f --- /dev/null +++ b/tests/roles/bootstrap-host/files/step_ca_x509_template.tpl @@ -0,0 +1,15 @@ +{ + "subject": { + "commonName": {{ toJson .Subject.CommonName }}, + "organizationalUnit": {{ toJson .OrganizationalUnit }}, + "organization": {{ toJson .Organization }}, + "country": {{ toJson .Country }} + }, + "sans": {{ toJson .SANs }}, +{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }} + "keyUsage": ["keyEncipherment", "digitalSignature"], +{{- else }} + "keyUsage": ["digitalSignature"], +{{- end }} + "extKeyUsage": ["serverAuth"] +} diff --git a/tests/roles/bootstrap-host/tasks/main.yml b/tests/roles/bootstrap-host/tasks/main.yml index bd9768af1a..1390a253f1 100644 --- a/tests/roles/bootstrap-host/tasks/main.yml +++ b/tests/roles/bootstrap-host/tasks/main.yml @@ -209,6 +209,19 @@ tags: - always +# Prepare local step-ca certificate authority +- include_tasks: prepare_step_ca.yml + when: + - "'stepca' in bootstrap_host_scenarios_expanded" + args: + apply: + tags: + - prepare-step-ca + tags: + - always + + + # Put the OpenStack-Ansible configuration for an All-In-One on the host - include_tasks: prepare_aio_config.yml when: diff --git a/tests/roles/bootstrap-host/tasks/prepare_step_ca.yml b/tests/roles/bootstrap-host/tasks/prepare_step_ca.yml new file mode 100644 index 0000000000..1294b28f07 --- /dev/null +++ b/tests/roles/bootstrap-host/tasks/prepare_step_ca.yml @@ -0,0 +1,119 @@ +--- +# Copyright 2023, BBC. +# +# 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. + +# This is packaged in ubuntu for Kinetic and later +- name: Install step-ca packages + package: + deb: "{{ (ansible_facts['pkg_mgr'] == 'apt') | ternary(item, omit) }}" + name: "{{ (ansible_facts['pkg_mgr'] == 'dnf') | ternary(item, omit) }}" + with_items: "{{ step_ca_package_urls }}" + +- name: Ensure user is present + user: + name: "{{ step_ca_user }}" + state: present + create_home: yes + home: "{{ step_ca_config_dir }}" + system: yes + shell: /bin/bash + +- name: Ensure group is present + group: + name: "{{ step_ca_group }}" + state: present + system: yes + +- name: Set STEPPATH variable to point to config directory to allow CLI commands to work + lineinfile: + dest: /etc/environment + line: 'STEPPATH="{{ step_ca_config_dir }}"' + state: present + +- name: Ensure that the config and db directories exists + file: + path: "{{ item }}" + state: directory + owner: "{{ step_ca_user }}" + group: "{{ step_ca_group }}" + recurse: true + with_items: + - "{{ step_ca_config_dir }}" + - "{{ step_ca_config_dir }}/config" + - "{{ step_ca_config_dir }}/db" + +- name: Ensure that the intermediate key password file is created + copy: + content: "{{ step_ca_intermediate_password }}" + dest: "{{ step_ca_config_dir}}/config/password.txt" + mode: 0600 + owner: "{{ step_ca_user }}" + +- name: Intialise Step-CA, only if config file doesn't exist + become: yes + become_user: "{{ step_ca_user }}" + command: > + step ca init + --name="{{ step_ca_name }}" + --dns="{{ step_ca_dns_name | join(',') }}" + --provisioner=delete-me + --password-file="{{ step_ca_config_dir}}/config/password.txt" + --address="{{ step_ca_listen_address }}" + args: + creates: "{{ step_ca_config_dir }}/config/ca.json" + +- name: Create systemd unit file + template: + src: step-ca.service.j2 + dest: /etc/systemd/system/step-ca.service + +- name: Restart step-ca to use initial configuration + systemd: + name: step-ca + state: restarted + daemon_reload: true + +- name: Create Go Template for x509 Certificate + copy: + src: step_ca_x509_template.tpl + dest: "{{ step_ca_config_dir }}/templates/x509_template.tpl" + owner: "{{ step_ca_user }}" + group: "{{ step_ca_group }}" + mode: 0600 + +- name: Check for ACME provisioner + become: yes + become_user: "{{ step_ca_user }}" + shell: 'step ca provisioner list | grep acme-osa' + failed_when: false + register: step_ca_find_provisioner + +- name: Create ACME provisioner + become: yes + become_user: "{{ step_ca_user }}" + command: > + step ca provisioner add acme-osa --type ACME + when: step_ca_find_provisioner.rc != 0 + +- name: Restart step-ca to use the ACME provisioner + systemd: + name: step-ca + state: restarted + when: step_ca_find_provisioner.rc != 0 + +- name: Retrieve the Root CA bundle from the CA server + get_url: + url: https://127.0.0.1:8889/roots.pem + validate_certs: false + dest: /opt/step_ca_roots.pem diff --git a/tests/roles/bootstrap-host/templates/step-ca.service.j2 b/tests/roles/bootstrap-host/templates/step-ca.service.j2 new file mode 100644 index 0000000000..3668932c56 --- /dev/null +++ b/tests/roles/bootstrap-host/templates/step-ca.service.j2 @@ -0,0 +1,50 @@ +[Unit] +Description=step-ca +Documentation=https://smallstep.com/docs/step-ca +Documentation=https://smallstep.com/docs/step-ca/certificate-authority-server-production +After=syslog.target network.target + +[Service] +Type=simple +User={{ step_ca_user }} +Group={{ step_ca_group }} +Environment=STEPPATH={{ step_ca_config_dir }} +WorkingDirectory={{ step_ca_config_dir }} +ExecStart=/bin/sh -c '{{ step_ca_binary }} {{ step_ca_config_dir }}/config/ca.json --password-file={{ step_ca_config_dir }}/config/password.txt' +ExecReload=/bin/kill --signal HUP $MAINPID +Restart=on-failure +RestartSec=10 +TimeoutStopSec=30 +StartLimitInterval=30 +StartLimitBurst=3 + +; Process capabilities & privileges +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +SecureBits=keep-caps +NoNewPrivileges=yes + + +; Sandboxing +ProtectSystem=full +ProtectHome=true +RestrictNamespaces=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +PrivateTmp=true +PrivateDevices=true +ProtectClock=true +ProtectControlGroups=true +ProtectKernelTunables=true +ProtectKernelLogs=true +ProtectKernelModules=true +LockPersonality=true +RestrictSUIDSGID=true +RemoveIPC=true +RestrictRealtime=true +SystemCallFilter=@system-service +SystemCallArchitectures=native +MemoryDenyWriteExecute=true +ReadWriteDirectories=/etc/step-ca/db + +[Install] +WantedBy=multi-user.target diff --git a/tests/roles/bootstrap-host/vars/debian.yml b/tests/roles/bootstrap-host/vars/debian.yml index 9fa5d8b837..ac59bf8629 100644 --- a/tests/roles/bootstrap-host/vars/debian.yml +++ b/tests/roles/bootstrap-host/vars/debian.yml @@ -46,3 +46,7 @@ rc_local: /etc/rc.local rc_local_insert_before: "^exit 0$" nfs_package: nfs-kernel-server + +step_ca_package_urls: + - 'https://github.com/smallstep/cli/releases/download/v0.23.4/step-cli_0.23.4_amd64.deb' + - 'https://github.com/smallstep/certificates/releases/download/v0.23.2/step-ca_0.23.2_amd64.deb' diff --git a/tests/roles/bootstrap-host/vars/redhat.yml b/tests/roles/bootstrap-host/vars/redhat.yml index 7e996d6e14..87c2cedf1b 100644 --- a/tests/roles/bootstrap-host/vars/redhat.yml +++ b/tests/roles/bootstrap-host/vars/redhat.yml @@ -31,3 +31,7 @@ rc_local: /etc/rc.d/rc.local rc_local_insert_before: "^touch /var/lock/subsys/local$" nfs_package: nfs-utils + +step_ca_package_urls: + - 'https://github.com/smallstep/cli/releases/download/v0.23.4/step-cli_0.23.4_amd64.rpm' + - 'https://github.com/smallstep/certificates/releases/download/v0.23.2/step-ca_0.23.2_386.rpm'