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
This commit is contained in:
Jonathan Rosser 2023-03-08 08:39:25 +00:00 committed by Damian Dabrowski
parent 1694b142bc
commit d1e27389b1
7 changed files with 225 additions and 0 deletions

View File

@ -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"

View File

@ -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"]
}

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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'