Initial Commit
Some checks failed
Lint Markdown files / markdown-lint (push) Successful in 11s
Ansible Linter / ansible-lint (push) Failing after 49s

This commit is contained in:
2025-07-30 22:09:38 +02:00
commit a0ea59c528
27 changed files with 2808 additions and 0 deletions

4
.ansible-lint Normal file
View File

@ -0,0 +1,4 @@
---
exclude_paths:
- .gitea/

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = false

View File

@ -0,0 +1,20 @@
name: Ansible Linter
on:
pull_request:
types: [ "opened", "reopened", "synchronize" ]
push:
branches: [ '**' ]
tags-ignore: [ '**' ]
jobs:
ansible-lint:
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ansible-lint
uses: ansible/ansible-lint@v25.6.1
with:
args: "--config-file .ansible-lint"
setup_python: "true"

View File

@ -0,0 +1,18 @@
name: Lint Markdown files
on:
pull_request:
types: [ "opened", "reopened", "synchronize" ]
push:
branches: [ '**' ]
tags-ignore: [ '**' ]
jobs:
markdown-lint:
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: DavidAnson/markdownlint-cli2-action@v20.0.0
with:
globs: '**/*.md'

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.ansible
node_modules

137
.markdownlint.yaml Normal file
View File

@ -0,0 +1,137 @@
# markdownlint YAML configuration
# https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml
# Default state for all rules
default: true
# Path to configuration file to extend
extends: null
# MD003/heading-style/header-style - Heading style
MD003:
# Heading style
style: "atx"
# MD004/ul-style - Unordered list style
MD004:
style: "dash"
# MD007/ul-indent - Unordered list indentation
MD007:
# Spaces for indent
indent: 2
# Whether to indent the first level of the list
start_indented: false
# MD009/no-trailing-spaces - Trailing spaces
MD009:
# Spaces for line break
br_spaces: 2
# Allow spaces for empty lines in list items
list_item_empty_lines: false
# Include unnecessary breaks
strict: false
# MD010/no-hard-tabs - Hard tabs
MD010:
# Include code blocks
code_blocks: true
# MD012/no-multiple-blanks - Multiple consecutive blank lines
MD012:
# Consecutive blank lines
maximum: 1
# MD013/line-length - Line length
MD013:
# Number of characters
line_length: 120
# Number of characters for headings
heading_line_length: 120
# Number of characters for code blocks
code_block_line_length: 120
# Include code blocks
code_blocks: false
# Include tables
tables: false
# Include headings
headings: true
# Strict length checking
strict: false
# Stern length checking
stern: false
# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines
MD022:
# Blank lines above heading
lines_above: 1
# Blank lines below heading
lines_below: 1
# MD025/single-title/single-h1 - Multiple top-level headings in the same document
MD025:
# Heading level
level: 1
# RegExp for matching title in front matter
front_matter_title: "^\\s*title\\s*[:=]"
# MD026/no-trailing-punctuation - Trailing punctuation in heading
MD026:
# Punctuation characters
punctuation: ".,;:!。,;:!"
# MD029/ol-prefix - Ordered list item prefix
MD029:
# List style
style: "one_or_ordered"
# MD030/list-marker-space - Spaces after list markers
MD030:
# Spaces for single-line unordered list items
ul_single: 1
# Spaces for single-line ordered list items
ol_single: 1
# Spaces for multi-line unordered list items
ul_multi: 1
# Spaces for multi-line ordered list items
ol_multi: 1
# MD033/no-inline-html - Inline HTML
MD033:
# Allowed elements
allowed_elements: []
# MD035/hr-style - Horizontal rule style
MD035:
# Horizontal rule style
style: "---"
# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading
MD036:
# Punctuation characters
punctuation: ".,;:!?。,;:!?"
# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading
MD041:
# Heading level
level: 1
# RegExp for matching title in front matter
front_matter_title: "^\\s*title\\s*[:=]"
# MD044/proper-names - Proper names should have the correct capitalization
MD044:
# List of proper names
names:
- gitea
# Include code blocks
code_blocks: false
# MD046/code-block-style - Code block style
MD046:
# Block style
style: "fenced"
# MD048/code-fence-style - Code fence style
MD048:
# Code fence syle
style: "backtick"

19
.yamllint.yaml Normal file
View File

@ -0,0 +1,19 @@
---
#
# Documentation:
# https://yamllint.readthedocs.io/en/stable/
#
rules:
brackets:
forbid: false
min-spaces-inside: 0
max-spaces-inside: 2
min-spaces-inside-empty: 0
max-spaces-inside-empty: 0
indentation:
spaces: 2
indent-sequences: false
line-length:
max: 360

20
LICENSE Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2025 Markus Pesch
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

69
README.md Normal file
View File

@ -0,0 +1,69 @@
# certificate-authority
This Ansible role can be used to create a root and intermediate certificate authority and issue client certificates from
them. Additionally offers the ansible role the feature to import the certificates of the authority into the systems
trust store.
## Examples
The following minimal example creates a root and intermediate certificate authority and issues a client certificate from
the intermediate certificate authority.
```yaml
certificate_authority_client_skip: false
certificate_authority_client_common_name: "{{ inventory_hostname }}"
certificate_authority_client_subject_alternative_names:
- "{{ inventory_hostname }}"
- san.example.local
```
## Parameters
### Root Certificate Authority (CA)
| Name | Description | Value |
| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| `certificate_authority_root_ca_skip` | Skip creation or import of a root certificate authority in general. | `false` |
| `certificate_authority_root_ca_create` | Create root certificate from scratch or import via `certificate_authority_root_ca_tls` prefixed variables. | `true` |
| `certificate_authority_root_ca_import` | Import the TLS certificate of the root certificate authority into the systems trust store. | `true` |
| `certificate_authority_root_ca_path` | Directory where the private and public TLS key of the root certificate authority should be stored. | `/etc/ansible-playbook/pki/ca` |
| `certificate_authority_root_ca_common_name` | Common Name (CN) of the root certificate authority. | `Ansible Root CA` |
| `certificate_authority_root_ca_subject_alternative_names` | Subject Alternative Names (SAN) of the root certificate authority. | `[]` |
| `certificate_authority_root_ca_not_after` | Time in the future from now when the TLS certificate should expire | `+3650d` |
| `certificate_authority_root_ca_not_before` | Time in the past from now when the TLS certificate should be valid. | `+0s` |
| `certificate_authority_root_ca_tls_key_content` | Content of a custom used root certificate authority. Will only be imported, when `certificate_authority_root_ca_create: false`. | `""` |
| `certificate_authority_root_ca_tls_crt_content` | Content of a custom used certificate of the certificate authority. Will only be imported, when `certificate_authority_root_ca_create: false`. | `""` |
| `certificate_authority_root_ca_tls_key_passphrase` | Passphrase for the private key of the generated or imported root certificate authority. | `""` |
| `certificate_authority_root_ca_tls_key_type` | Algorithm of the private key of the root certificate authority. | `RSA` |
### Intermediate Certificate Authority (CA)
| Name | Description | Value |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| `certificate_authority_intermediate_ca_skip` | Skip creation or import of a intermediate certificate authority in general. | `false` |
| `certificate_authority_intermediate_ca_create` | Create intermediate certificate from scratch or import via `certificate_authority_intermediate_ca_tls` prefixed variables. | `true` |
| `certificate_authority_intermediate_ca_path` | Directory where the private and public TLS key of the intermediate certificate authority should be stored. | `/etc/ansible-playbook/pki/intermediate` |
| `certificate_authority_intermediate_ca_common_name` | Common Name (CN) of the intermediate certificate authority. | `Ansible Intermediate CA` |
| `certificate_authority_intermediate_ca_subject_alternative_names` | Subject Alternative Names (SAN) of the intermediate certificate authority. | `[]` |
| `certificate_authority_intermediate_ca_not_after` | Time in the future from now when the TLS certificate should expire | `+1825d` |
| `certificate_authority_intermediate_ca_not_before` | Time in the past from now when the TLS certificate should be valid. | `+0s` |
| `certificate_authority_intermediate_ca_tls_key_content` | Content of a custom used intermediate certificate authority. Will only be imported, when `certificate_authority_intermediate_ca_create: false`. | `""` |
| `certificate_authority_intermediate_ca_tls_crt_content` | Content of a custom used certificate of the certificate authority. Will only be imported, when `certificate_authority_intermediate_ca_create: false`. | `""` |
| `certificate_authority_intermediate_ca_tls_key_passphrase` | Passphrase for the private key of the generated or imported intermediate certificate authority. | `""` |
| `certificate_authority_intermediate_ca_tls_key_type` | Algorithm of the private key of the intermediate certificate authority. | `RSA` |
### Client Certificate
| Name | Description | Value |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------- |
| `certificate_authority_client_skip` | Skip creation or import of a client certificate in general. | `true` |
| `certificate_authority_client_create` | Create client certificate from scratch or import via `certificate_authority_client_tls` prefixed variables. | `true` |
| `certificate_authority_client_path` | Directory where the private and public TLS key of the client certificate authority should be stored. | `/etc/ansible-playbook/pki/client` |
| `certificate_authority_client_common_name` | Common Name (CN) of the client certificate. | `Ansible Client Certificate` |
| `certificate_authority_client_subject_alternative_names` | Subject Alternative Names (SAN) of the client certificate. | `[]` |
| `certificate_authority_client_not_after` | Time in the future from now when the TLS certificate should expire | `+397d` |
| `certificate_authority_client_not_before` | Time in the past from now when the TLS certificate should be valid. | `+0s` |
| `certificate_authority_client_tls_key_passphrase` | Passphrase for the private key of the generated or imported client certificate. | `""` |
| `certificate_authority_client_tls_key_type` | Algorithm of the private key of the client certificate. | `RSA` |
| `certificate_authority_client_tls_crt_content` | Passphrase for the private key of the generated or imported client certificate. | `""` |
| `certificate_authority_client_tls_key_content` | Algorithm of the private key of the client certificate | `""` |

86
defaults/main.yaml Normal file
View File

@ -0,0 +1,86 @@
---
## @section Root Certificate Authority (CA)
## @param certificate_authority_root_ca_skip Skip creation or import of a root certificate authority in general.
## @param certificate_authority_root_ca_create Create root certificate from scratch or import via `certificate_authority_root_ca_tls` prefixed variables.
## @param certificate_authority_root_ca_import Import the TLS certificate of the root certificate authority into the systems trust store.
certificate_authority_root_ca_skip: false
certificate_authority_root_ca_create: true
certificate_authority_root_ca_import: true
## @param certificate_authority_root_ca_path Directory where the private and public TLS key of the root certificate authority should be stored.
## @param certificate_authority_root_ca_common_name Common Name (CN) of the root certificate authority.
## @param certificate_authority_root_ca_subject_alternative_names Subject Alternative Names (SAN) of the root certificate authority.
## @param certificate_authority_root_ca_not_after Time in the future from now when the TLS certificate should expire
## @param certificate_authority_root_ca_not_before Time in the past from now when the TLS certificate should be valid.
certificate_authority_root_ca_path: "/etc/ansible-playbook/pki/ca"
certificate_authority_root_ca_common_name: "Ansible Root CA"
certificate_authority_root_ca_subject_alternative_names: []
certificate_authority_root_ca_not_after: "+3650d"
certificate_authority_root_ca_not_before: "+0s"
## @param certificate_authority_root_ca_tls_key_content Content of a custom used root certificate authority. Will only be imported, when `certificate_authority_root_ca_create: false`.
## @param certificate_authority_root_ca_tls_crt_content Content of a custom used certificate of the certificate authority. Will only be imported, when `certificate_authority_root_ca_create: false`.
certificate_authority_root_ca_tls_key_content: ""
certificate_authority_root_ca_tls_crt_content: ""
## @param certificate_authority_root_ca_tls_key_passphrase Passphrase for the private key of the generated or imported root certificate authority.
## @param certificate_authority_root_ca_tls_key_type Algorithm of the private key of the root certificate authority.
certificate_authority_root_ca_tls_key_passphrase: ""
certificate_authority_root_ca_tls_key_type: "RSA"
## @section Intermediate Certificate Authority (CA)
## @param certificate_authority_intermediate_ca_skip Skip creation or import of a intermediate certificate authority in general.
## @param certificate_authority_intermediate_ca_create Create intermediate certificate from scratch or import via `certificate_authority_intermediate_ca_tls` prefixed variables.
certificate_authority_intermediate_ca_skip: false
certificate_authority_intermediate_ca_create: true
## @param certificate_authority_intermediate_ca_path Directory where the private and public TLS key of the intermediate certificate authority should be stored.
## @param certificate_authority_intermediate_ca_common_name Common Name (CN) of the intermediate certificate authority.
## @param certificate_authority_intermediate_ca_subject_alternative_names Subject Alternative Names (SAN) of the intermediate certificate authority.
## @param certificate_authority_intermediate_ca_not_after Time in the future from now when the TLS certificate should expire
## @param certificate_authority_intermediate_ca_not_before Time in the past from now when the TLS certificate should be valid.
certificate_authority_intermediate_ca_path: "/etc/ansible-playbook/pki/intermediate"
certificate_authority_intermediate_ca_common_name: "Ansible Intermediate CA"
certificate_authority_intermediate_ca_subject_alternative_names: []
certificate_authority_intermediate_ca_not_after: "+1825d"
certificate_authority_intermediate_ca_not_before: "+0s"
## @param certificate_authority_intermediate_ca_tls_key_content Content of a custom used intermediate certificate authority. Will only be imported, when `certificate_authority_intermediate_ca_create: false`.
## @param certificate_authority_intermediate_ca_tls_crt_content Content of a custom used certificate of the certificate authority. Will only be imported, when `certificate_authority_intermediate_ca_create: false`.
certificate_authority_intermediate_ca_tls_key_content: ""
certificate_authority_intermediate_ca_tls_crt_content: ""
## @param certificate_authority_intermediate_ca_tls_key_passphrase Passphrase for the private key of the generated or imported intermediate certificate authority.
## @param certificate_authority_intermediate_ca_tls_key_type Algorithm of the private key of the intermediate certificate authority.
certificate_authority_intermediate_ca_tls_key_passphrase: ""
certificate_authority_intermediate_ca_tls_key_type: "RSA"
## @section Client Certificate
## @param certificate_authority_client_skip Skip creation or import of a client certificate in general.
## @param certificate_authority_client_create Create client certificate from scratch or import via `certificate_authority_client_tls` prefixed variables.
certificate_authority_client_skip: true
certificate_authority_client_create: true
## @param certificate_authority_client_path Directory where the private and public TLS key of the client certificate authority should be stored.
## @param certificate_authority_client_common_name Common Name (CN) of the client certificate.
## @param certificate_authority_client_subject_alternative_names Subject Alternative Names (SAN) of the client certificate.
## @param certificate_authority_client_not_after Time in the future from now when the TLS certificate should expire
## @param certificate_authority_client_not_before Time in the past from now when the TLS certificate should be valid.
certificate_authority_client_path: "/etc/ansible-playbook/pki/client"
certificate_authority_client_common_name: "Ansible Client Certificate"
certificate_authority_client_subject_alternative_names: []
certificate_authority_client_not_after: "+397d"
certificate_authority_client_not_before: "+0s"
## @param certificate_authority_client_tls_key_passphrase Passphrase for the private key of the generated or imported client certificate.
## @param certificate_authority_client_tls_key_type Algorithm of the private key of the client certificate.
certificate_authority_client_tls_key_passphrase: ""
certificate_authority_client_tls_key_type: "RSA"
## @param certificate_authority_client_tls_crt_content Passphrase for the private key of the generated or imported client certificate.
## @param certificate_authority_client_tls_key_content Algorithm of the private key of the client certificate
certificate_authority_client_tls_crt_content: ""
certificate_authority_client_tls_key_content: ""

25
meta/main.yml Normal file
View File

@ -0,0 +1,25 @@
galaxy_info:
namespace: volker-raschek
role_name: "certificate_authority"
author: "Markus Pesch"
description: "Role to create and managed an existing PKI infrastructure"
company: "Cryptic Systems"
license: "MIT"
min_ansible_version: "2.9"
platforms:
- name: ArchLinux
versions:
- all
- name: Ubuntu
versions:
- all
- name: Fedora
versions:
- "35"
galaxy_tags:
- certificate-authority
- ca
- ssl
- tls
dependencies: []

1732
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "certificate-authority-ansible-role",
"homepage": "https://git.cryptic.systems/volker.raschel/certificate-authority-ansible-role.git",
"license": "MIT",
"private": true,
"engineStrict": true,
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"scripts": {
"readme:lint": "markdownlint *.md -f",
"readme:parameters": "readme-generator -v defaults/main.yaml -r README.md"
},
"devDependencies": {
"@bitnami/readme-generator-for-helm": "^2.5.0",
"markdownlint-cli": "^0.45.0"
}
}

9
renovate.json Normal file
View File

@ -0,0 +1,9 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"local>volker.raschek/renovate-config:default#master",
"local>volker.raschek/renovate-config:container#master",
"local>volker.raschek/renovate-config:actions#master",
"local>volker.raschek/renovate-config:regexp#master"
]
}

View File

@ -0,0 +1,112 @@
---
- name: Create directory to store tls keys and certificates of the client
ansible.builtin.file:
path: "{{ certificate_authority_client_path }}"
owner: "root"
group: "root"
mode: "0700"
state: directory
- name: Create unprotected client certificate
ansible.builtin.include_tasks: client_certificate_unprotected.yaml
when: certificate_authority_client_create is defined and
certificate_authority_client_create and
certificate_authority_client_tls_key_passphrase is defined and
certificate_authority_client_tls_key_passphrase | length <= 0
- name: Create passphrase protected client certificate
ansible.builtin.include_tasks: client_certificate_unprotected.yaml
when: certificate_authority_client_create is defined and
certificate_authority_client_create and
certificate_authority_client_tls_key_passphrase is defined and
certificate_authority_client_tls_key_passphrase | length > 0
- name: Import client certificate
ansible.builtin.include_tasks: client_certificate_import.yaml
when: certificate_authority_client_create is defined and
not certificate_authority_client_create
- name: Create certificate chain file
block:
- name: Check if intermediate certificate exists
ansible.builtin.stat:
path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
register: _stat_result
- name: Concatenate client certificate and intermediate certificate
vars:
_chain_files:
- "{{ certificate_authority_client_path }}/cert.pem"
- "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
ansible.builtin.command:
cmd: awk 1 {{ _chain_files | join(' ') }}
register: chain_content
changed_when: chain_content.rc == 0
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create concatenated chain file
ansible.builtin.copy:
content: "{{ chain_content.stdout_lines | join('\n') }}"
dest: "{{ certificate_authority_client_path }}/chain.pem"
owner: "root"
group: "root"
mode: "0644"
remote_src: true
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create certificate fullchain file
block:
- name: Check if intermediate chain exists
ansible.builtin.stat:
path: "{{ certificate_authority_intermediate_ca_path }}/chain.pem"
register: _stat_result
- name: Concatenate client certificate and intermediate chain file
vars:
_chain_files:
- "{{ certificate_authority_client_path }}/cert.pem"
- "{{ certificate_authority_intermediate_ca_path }}/chain.pem"
ansible.builtin.command:
cmd: awk 1 {{ _chain_files | join(' ') }}
register: chain_content
changed_when: chain_content.rc == 0
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create concatenated fullchain file
ansible.builtin.copy:
content: "{{ chain_content.stdout_lines | join('\n') }}"
dest: "{{ certificate_authority_client_path }}/fullchain.pem"
owner: "root"
group: "root"
mode: "0644"
remote_src: true
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create file with private key and fullchain file of the client
block:
- name: Check if fullchain exists
ansible.builtin.stat:
path: "{{ certificate_authority_client_path }}/fullchain.pem"
register: _stat_result
- name: Concatenate private key and fullchain file of the client
vars:
_chain_files:
- "{{ certificate_authority_client_path }}/privkey.pem"
- "{{ certificate_authority_client_path }}/fullchain.pem"
ansible.builtin.command:
cmd: awk 1 {{ _chain_files | join(' ') }}
register: chain_content
changed_when: chain_content.rc == 0
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create concatenated file
ansible.builtin.copy:
content: "{{ chain_content.stdout_lines | join('\n') }}"
dest: "{{ certificate_authority_client_path }}/all.pem"
owner: "root"
group: "root"
mode: "0600"
remote_src: true
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists

View File

@ -0,0 +1,19 @@
---
- name: Import private key of a client
ansible.builtin.copy:
content: "{{ certificate_authority_client_tls_key_content }}"
dest: "{{ certificate_authority_client_ca_path }}/privkey.pem"
owner: "root"
group: "root"
mode: "0600"
when: certificate_authority_client_tls_key_content | length > 0
- name: Import certificate of a client
ansible.builtin.copy:
content: "{{ certificate_authority_client_tls_crt_content }}"
dest: "{{ certificate_authority_client_tls_crt_content }}/cert.pem"
owner: "root"
group: "root"
mode: "0644"
when: certificate_authority_client_tls_crt_content | length > 0

View File

@ -0,0 +1,59 @@
---
- name: Create private key for client
community.crypto.openssl_privatekey:
path: "{{ certificate_authority_client_path }}/privkey.pem"
type: "{{ certificate_authority_client_tls_key_type }}"
passphrase: "{{ certificate_authority_client_tls_key_passphrase }}"
- name: Create a certificate signing request (CSR) for client certificate without subject alternative names (SANs)
community.crypto.openssl_csr:
common_name: "{{ certificate_authority_client_common_name }}"
extendedKeyUsage:
- clientAuth
- serverAuth
path: "{{ certificate_authority_client_path }}/cert-req.pem"
privatekey_passphrase: "{{ certificate_authority_client_tls_key_passphrase }}"
privatekey_path: "{{ certificate_authority_client_path }}/privkey.pem"
when: |
certificate_authority_client_subject_alternative_names is not defined or
(certificate_authority_client_subject_alternative_names is defined and
certificate_authority_client_subject_alternative_names | length <= 0)
- name: Create a certificate signing request (CSR) for client certificate with subject alternative names (SANs)
community.crypto.openssl_csr:
common_name: "{{ certificate_authority_client_common_name }}"
extendedKeyUsage:
- clientAuth
- serverAuth
path: "{{ certificate_authority_client_path }}/cert-req.pem"
privatekey_path: "{{ certificate_authority_client_path }}/privkey.pem"
privatekey_passphrase: "{{ certificate_authority_client_tls_key_passphrase }}"
subject_alt_name: "{{ certificate_authority_client_subject_alternative_names | map('regex_replace', '^', 'DNS:') | list | join(',') | quote }}"
when: certificate_authority_client_subject_alternative_names is defined and
certificate_authority_client_subject_alternative_names | length > 0
- name: Create signed client certificate - unprotected intermediate Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_client_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_client_not_after }}"
ownca_not_before: "{{ certificate_authority_client_not_before }}"
ownca_path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
ownca_privatekey_path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
path: "{{ certificate_authority_client_path }}/cert.pem"
privatekey_passphrase: "{{ certificate_authority_client_tls_key_passphrase }}"
provider: ownca
when: certificate_authority_intermediate_ca_tls_key_passphrase | length <= 0
- name: Create signed client certificate - passphrase protected intermediate Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_client_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_client_not_after }}"
ownca_not_before: "{{ certificate_authority_client_not_before }}"
ownca_path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
ownca_privatekey_passphrase: "{{ certificate_authority_intermediate_ca_tls_key_passphrase }}"
ownca_privatekey_path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
path: "{{ certificate_authority_client_path }}/cert.pem"
privatekey_passphrase: "{{ certificate_authority_client_tls_key_passphrase }}"
provider: ownca
when: certificate_authority_intermediate_ca_tls_key_passphrase | length > 0

View File

@ -0,0 +1,54 @@
---
- name: Create private key for client
community.crypto.openssl_privatekey:
path: "{{ certificate_authority_client_path }}/privkey.pem"
type: "{{ certificate_authority_client_tls_key_type }}"
- name: Create a certificate signing request (CSR) for client certificate without subject alternative names (SANs)
community.crypto.openssl_csr:
common_name: "{{ certificate_authority_client_common_name }}"
extendedKeyUsage:
- clientAuth
- serverAuth
path: "{{ certificate_authority_client_path }}/cert-req.pem"
privatekey_path: "{{ certificate_authority_client_path }}/privkey.pem"
when: |
certificate_authority_client_subject_alternative_names is not defined or
(certificate_authority_client_subject_alternative_names is defined and
certificate_authority_client_subject_alternative_names | length <= 0)
- name: Create a certificate signing request (CSR) for client certificate with subject alternative names (SANs)
community.crypto.openssl_csr:
common_name: "{{ certificate_authority_client_common_name }}"
extendedKeyUsage:
- clientAuth
- serverAuth
path: "{{ certificate_authority_client_path }}/cert-req.pem"
privatekey_path: "{{ certificate_authority_client_path }}/privkey.pem"
subject_alt_name: "{{ certificate_authority_client_subject_alternative_names | map('regex_replace', '^', 'DNS:') | list | join(',') | quote }}"
when: certificate_authority_client_subject_alternative_names is defined and
certificate_authority_client_subject_alternative_names | length > 0
- name: Create signed client certificate - unprotected intermediate Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_client_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_client_not_after }}"
ownca_not_before: "{{ certificate_authority_client_not_before }}"
ownca_path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
ownca_privatekey_path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
path: "{{ certificate_authority_client_path }}/cert.pem"
provider: ownca
when: certificate_authority_intermediate_ca_tls_key_passphrase | length <= 0
- name: Create signed client certificate - passphrase protected intermediate Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_client_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_client_not_after }}"
ownca_not_before: "{{ certificate_authority_client_not_before }}"
ownca_path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
ownca_privatekey_passphrase: "{{ certificate_authority_intermediate_ca_tls_key_passphrase }}"
ownca_privatekey_path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
path: "{{ certificate_authority_client_path }}/cert.pem"
provider: ownca
when: certificate_authority_intermediate_ca_tls_key_passphrase | length > 0

View File

@ -0,0 +1,112 @@
---
- name: Create directory to store tls keys and certificates of the intermediate CA
ansible.builtin.file:
path: "{{ certificate_authority_intermediate_ca_path }}"
owner: "root"
group: "root"
mode: "0700"
state: "directory"
- name: Create unprotected intermediate Certificate Authority (CA)
ansible.builtin.include_tasks: intermediate_certificate_authority_unprotected.yaml
when: certificate_authority_intermediate_ca_create is defined and
certificate_authority_intermediate_ca_create and
certificate_authority_intermediate_ca_tls_key_passphrase is defined and
certificate_authority_intermediate_ca_tls_key_passphrase | length <= 0
- name: Create passphrase protected intermediate Certificate Authority (CA)
ansible.builtin.include_tasks: intermediate_certificate_authority_unprotected.yaml
when: certificate_authority_intermediate_ca_create is defined and
certificate_authority_intermediate_ca_create and
certificate_authority_intermediate_ca_tls_key_passphrase is defined and
certificate_authority_intermediate_ca_tls_key_passphrase | length > 0
- name: Import intermediate Certificate Authority (CA)
ansible.builtin.include_tasks: intermediate_certificate_authority_import.yaml
when: certificate_authority_intermediate_ca_create is defined and
not certificate_authority_intermediate_ca_create
- name: Create certificate chain file
block:
- name: Check if root certificate exists
ansible.builtin.stat:
path: "{{ certificate_authority_root_ca_path }}/cert.pem"
register: _stat_result
- name: Concatenate intermediate certificate and root certificate
vars:
_chain_files:
- "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
- "{{ certificate_authority_root_ca_path }}/cert.pem"
ansible.builtin.command:
cmd: awk 1 {{ _chain_files | join(' ') }}
register: chain_content
changed_when: chain_content.rc == 0
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create concatenated chain file
ansible.builtin.copy:
content: "{{ chain_content.stdout_lines | join('\n') }}"
dest: "{{ certificate_authority_intermediate_ca_path }}/chain.pem"
owner: "root"
group: "root"
mode: "0644"
remote_src: true
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create certificate fullchain file
block:
- name: Check if root chain exists
ansible.builtin.stat:
path: "{{ certificate_authority_root_ca_path }}/chain.pem"
register: _stat_result
- name: Concatenate intermediate certificate and root chain file
vars:
_chain_files:
- "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
- "{{ certificate_authority_root_ca_path }}/chain.pem"
ansible.builtin.command:
cmd: awk 1 {{ _chain_files | join(' ') }}
register: chain_content
changed_when: chain_content.rc == 0
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create concatenated fullchain file
ansible.builtin.copy:
content: "{{ chain_content.stdout_lines | join('\n') }}"
dest: "{{ certificate_authority_intermediate_ca_path }}/fullchain.pem"
owner: "root"
group: "root"
mode: "0644"
remote_src: true
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create file with private key and fullchain file of intermediate Certificate Authority (CA)
block:
- name: Check if private key exists
ansible.builtin.stat:
path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
register: _stat_result
- name: Concatenate private key and fullchain file of intermediate Certificate Authority (CA)
vars:
_chain_files:
- "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
- "{{ certificate_authority_intermediate_ca_path }}/fullchain.pem"
ansible.builtin.command:
cmd: awk 1 {{ _chain_files | join(' ') }}
register: chain_content
changed_when: chain_content.rc == 0
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create concatenated file
ansible.builtin.copy:
content: "{{ chain_content.stdout_lines | join('\n') }}"
dest: "{{ certificate_authority_intermediate_ca_path }}/all.pem"
owner: "root"
group: "root"
mode: "0600"
remote_src: true
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists

View File

@ -0,0 +1,19 @@
---
- name: Import private key of intermediate Certificate Authority (CA)
ansible.builtin.copy:
content: "{{ certificate_authority_intermediate_ca_tls_key_content }}"
dest: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
owner: root
group: root
mode: "0600"
when: certificate_authority_intermediate_ca_tls_key_content | length > 0
- name: Import certificate of intermediate Certificate Authority (CA)
ansible.builtin.copy:
content: "{{ certificate_authority_intermediate_ca_tls_crt_content }}"
dest: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
owner: root
group: root
mode: "0644"
when: certificate_authority_intermediate_ca_tls_crt_content | length > 0

View File

@ -0,0 +1,44 @@
---
- name: Create private key for intermediate CA
community.crypto.openssl_privatekey:
passphrase: "{{ certificate_authority_intermediate_ca_tls_key_passphrase }}"
path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
type: "{{ certificate_authority_intermediate_ca_tls_key_type }}"
- name: Create a certificate signing request (CSR) for intermediate CA
community.crypto.openssl_csr:
basic_constraints:
- "CA:TRUE"
common_name: "{{ certificate_authority_intermediate_ca_common_name }}"
path: "{{ certificate_authority_intermediate_ca_path }}/cert-req.pem"
privatekey_passphrase: "{{ certificate_authority_intermediate_ca_tls_key_passphrase }}"
privatekey_path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
use_common_name_for_san: false
- name: Create signed client certificate - unprotected root Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_intermediate_ca_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_intermediate_ca_not_after }}"
ownca_not_before: "{{ certificate_authority_intermediate_ca_not_before }}"
ownca_path: "{{ certificate_authority_root_ca_path }}/cert.pem"
ownca_privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
privatekey_passphrase: "{{ certificate_authority_intermediate_ca_tls_key_passphrase }}"
provider: ownca
when: certificate_authority_root_ca_tls_key_passphrase is defined and
certificate_authority_root_ca_tls_key_passphrase | length <= 0
- name: Create signed client certificate - passphrase protected root Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_intermediate_ca_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_intermediate_ca_not_after }}"
ownca_not_before: "{{ certificate_authority_intermediate_ca_not_before }}"
ownca_path: "{{ certificate_authority_root_ca_path }}/cert.pem"
ownca_privatekey_passphrase: "{{ certificate_authority_root_ca_tls_key_passphrase }}"
ownca_privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
privatekey_passphrase: "{{ certificate_authority_intermediate_ca_tls_key_passphrase }}"
provider: ownca
when: certificate_authority_root_ca_tls_key_passphrase is defined and
certificate_authority_root_ca_tls_key_passphrase | length > 0

View File

@ -0,0 +1,38 @@
---
- name: Create private key for intermediate CA
community.crypto.openssl_privatekey:
path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
type: "{{ certificate_authority_intermediate_ca_tls_key_type }}"
- name: Create a certificate signing request (CSR) for intermediate CA
community.crypto.openssl_csr:
basic_constraints:
- "CA:TRUE"
common_name: "{{ certificate_authority_intermediate_ca_common_name }}"
path: "{{ certificate_authority_intermediate_ca_path }}/cert-req.pem"
privatekey_path: "{{ certificate_authority_intermediate_ca_path }}/privkey.pem"
use_common_name_for_san: false
- name: Create signed client certificate - unprotected root Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_intermediate_ca_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_intermediate_ca_not_after }}"
ownca_not_before: "{{ certificate_authority_intermediate_ca_not_before }}"
ownca_path: "{{ certificate_authority_root_ca_path }}/cert.pem"
ownca_privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
provider: ownca
when: certificate_authority_root_ca_tls_key_passphrase | length <= 0
- name: Create signed client certificate - passphrase protected root Certificate Authority (CA)
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_intermediate_ca_path }}/cert-req.pem"
ownca_not_after: "{{ certificate_authority_intermediate_ca_not_after }}"
ownca_not_before: "{{ certificate_authority_intermediate_ca_not_before }}"
ownca_path: "{{ certificate_authority_root_ca_path }}/cert.pem"
ownca_privatekey_passphrase: "{{ certificate_authority_root_ca_tls_key_passphrase }}"
ownca_privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
path: "{{ certificate_authority_intermediate_ca_path }}/cert.pem"
provider: ownca
when: certificate_authority_root_ca_tls_key_passphrase | length > 0

26
tasks/main.yaml Normal file
View File

@ -0,0 +1,26 @@
---
- name: Upgrade python package manager pip
ansible.builtin.pip:
name: pip
state: latest
- name: Install required python library cryptography
ansible.builtin.pip:
name: cryptography>=1.2.3
state: present
- name: Create or import a root Certificate Authority (CA)
ansible.builtin.include_tasks: root_certificate_authority.yaml
when: certificate_authority_root_ca_skip is defined and
not certificate_authority_root_ca_skip
- name: Create or import a intermediate Certificate Authority (CA)
ansible.builtin.include_tasks: intermediate_certificate_authority.yaml
when: certificate_authority_intermediate_ca_skip is defined and
not certificate_authority_intermediate_ca_skip
- name: Create or import a client certificate
ansible.builtin.include_tasks: client_certificate.yaml
when: certificate_authority_client_skip is defined and
not certificate_authority_client_skip

View File

@ -0,0 +1,84 @@
---
- name: Create directory to store tls keys and certificates of the root CA
ansible.builtin.file:
path: "{{ certificate_authority_root_ca_path }}"
owner: "root"
group: "root"
mode: "0700"
state: "directory"
- name: Create unprotected root Certificate Authority (CA)
ansible.builtin.include_tasks: root_certificate_authority_unprotected.yaml
when: certificate_authority_root_ca_create is defined and
certificate_authority_root_ca_create and
certificate_authority_root_ca_tls_key_passphrase is defined and
certificate_authority_root_ca_tls_key_passphrase | length <= 0
- name: Create passphrase protected root Certificate Authority (CA)
ansible.builtin.include_tasks: root_certificate_authority_unprotected.yaml
when: certificate_authority_root_ca_create is defined and
certificate_authority_root_ca_create and
certificate_authority_root_ca_tls_key_passphrase is defined and
certificate_authority_root_ca_tls_key_passphrase | length > 0
- name: Import protected root Certificate Authority (CA)
ansible.builtin.include_tasks: root_certificate_authority_import.yaml
when: certificate_authority_root_ca_create is defined and
not certificate_authority_root_ca_create
- name: Create symbolic link for signed root certificate
ansible.builtin.file:
src: "{{ certificate_authority_root_ca_path }}/cert.pem"
dest: "{{ certificate_authority_root_ca_path }}/{{ item }}"
state: link
with_items:
- ca.pem
- chain.pem
- fullchain.pem
- name: Create file with private key and fullchain file of root Certificate Authority (CA)
block:
- name: Check if private key exists
ansible.builtin.stat:
path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
register: _stat_result
- name: Concatenate private key and fullchain file of root Certificate Authority (CA)
vars:
_chain_files:
- "{{ certificate_authority_root_ca_path }}/privkey.pem"
- "{{ certificate_authority_root_ca_path }}/fullchain.pem"
ansible.builtin.command:
cmd: awk 1 {{ _chain_files | join(' ') }}
register: chain_content
changed_when: chain_content.rc == 0
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Create concatenated file
ansible.builtin.copy:
content: "{{ chain_content.stdout_lines | join('\n') }}"
dest: "{{ certificate_authority_root_ca_path }}/all.pem"
owner: "root"
group: "root"
mode: "0600"
remote_src: true
when: _stat_result.stat.exists is defined and
_stat_result.stat.exists
- name: Import certificate of root Certificate Authority (CA) into systems trust store
when: certificate_authority_root_ca_import is defined and
certificate_authority_root_ca_import
block:
- name: Create symolic link
ansible.builtin.file:
src: "{{ certificate_authority_root_ca_path }}/cert.pem"
dest: "/etc/pki/ca-trust/source/anchors/{{ certificate_authority_root_ca_common_name | replace(' ', '_') }}.pem"
owner: root
group: root
state: link
- name: Update systems SSL/TLS trust store
ansible.builtin.command:
cmd: /usr/bin/update-ca-trust
register: _update_ca_trust
changed_when: _update_ca_trust.rc == 0
failed_when: _update_ca_trust.rc > 0

View File

@ -0,0 +1,19 @@
---
- name: Import private key of root Certificate Authority (CA)
ansible.builtin.copy:
content: "{{ certificate_authority_root_ca_tls_key_content }}"
dest: "{{ certificate_authority_root_ca_path }}/privkey.pem"
owner: root
group: root
mode: "0600"
when: certificate_authority_root_ca_tls_key_content | length > 0
- name: Import certificate of root Certificate Authority (CA)
ansible.builtin.copy:
content: "{{ certificate_authority_root_ca_tls_crt_content }}"
dest: "{{ certificate_authority_root_ca_path }}/cert.pem"
owner: "root"
group: "root"
mode: "0644"
when: certificate_authority_root_ca_tls_crt_content | length > 0

View File

@ -0,0 +1,26 @@
---
- name: Create private key for root CA
community.crypto.openssl_privatekey:
passphrase: "{{ certificate_authority_root_ca_tls_key_passphrase }}"
path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
type: "{{ certificate_authority_root_ca_tls_key_type }}"
- name: Create a certificate signing request (CSR) for root CA
community.crypto.openssl_csr:
basic_constraints:
- "CA:TRUE"
common_name: "{{ certificate_authority_root_ca_common_name }}"
path: "{{ certificate_authority_root_ca_path }}/cert-req.pem"
privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
use_common_name_for_san: false
- name: Create self-signed certificate for root CA
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_root_ca_path }}/cert-req.pem"
path: "{{ certificate_authority_root_ca_path }}/cert.pem"
privatekey_passphrase: "{{ certificate_authority_root_ca_tls_key_passphrase }}"
privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
provider: selfsigned
selfsigned_not_after: "{{ certificate_authority_root_ca_not_after }}"
selfsigned_not_before: "{{ certificate_authority_root_ca_not_before }}"

View File

@ -0,0 +1,24 @@
---
- name: Create private key for root CA
community.crypto.openssl_privatekey:
path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
type: "{{ certificate_authority_root_ca_tls_key_type }}"
- name: Create a certificate signing request (CSR) for root CA
community.crypto.openssl_csr:
basic_constraints:
- "CA:TRUE"
common_name: "{{ certificate_authority_root_ca_common_name }}"
path: "{{ certificate_authority_root_ca_path }}/cert-req.pem"
privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
use_common_name_for_san: false
- name: Create self-signed certificate for root CA
community.crypto.x509_certificate:
csr_path: "{{ certificate_authority_root_ca_path }}/cert-req.pem"
path: "{{ certificate_authority_root_ca_path }}/cert.pem"
privatekey_path: "{{ certificate_authority_root_ca_path }}/privkey.pem"
provider: selfsigned
selfsigned_not_after: "{{ certificate_authority_root_ca_not_after }}"
selfsigned_not_before: "{{ certificate_authority_root_ca_not_before }}"