Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some guides #237

Merged
merged 6 commits into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions docs/docsite/extra-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
sections:
- title: Scenario Guides
toctree:
- guide_selfsigned
- guide_ownca
148 changes: 148 additions & 0 deletions docs/docsite/rst/guide_ownca.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
.. _ansible_collections.community.crypto.docsite.guide_ownca:

How to create a small CA
========================

The `community.crypto collection <https://galaxy.ansible.com/community/crypto>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create your own small CA and how to use it to sign certificates.

In all examples, we assume that the CA's private key is password protected, where the password is provided in the ``secret_ca_passphrase`` variable.

Set up the CA
-------------

Any certificate can be used as a CA certificate. You can create a self-signed certificate (see :ref:`ansible_collections.community.crypto.docsite.guide_selfsigned`), use another CA certificate to sign a new certificate (using the instructions below for signing a certificate), ask (and pay) a commercial CA to sign your CA certificate, etc.

The following instructions show how to set up a simple self-signed CA certificate.

.. code-block:: yaml+jinja

- name: Create private key with password protection
community.crypto.openssl_privatekey:
path: /path/to/ca-certificate.key
passphrase: "{{ secret_ca_passphrase }}"

- name: Create certificate signing request (CSR) for CA certificate
community.crypto.openssl_csr_pipe:
privatekey_path: /path/to/ca-certificate.key
privatekey_passphrase: "{{ secret_ca_passphrase }}"
common_name: Ansible CA
use_common_name_for_san: false # since we do not specify SANs, don't use CN as a SAN
basic_constraints:
- 'CA:TRUE'
basic_constraints_critical: yes
key_usage:
- keyCertSign
key_usage_critical: true
register: ca_csr

- name: Create self-signed CA certificate from CSR
community.crypto.x509_certificate:
path: /path/to/ca-certificate.pem
csr_content: "{{ ca_csr.csr }}"
privatekey_path: /path/to/ca-certificate.key
privatekey_passphrase: "{{ secret_ca_passphrase }}"
provider: selfsigned

Use the CA to sign a certificate
--------------------------------

To sign a certificate, you must pass a CSR to the :ref:`community.crypto.x509_certificate module <ansible_collections.community.crypto.x509_certificate_module>` or :ref:`community.crypto.x509_certificate_pipe module <ansible_collections.community.crypto.x509_certificate_pipe_module>`.

In the following example, we assume that the certificate to sign (including its private key) are on ``server_1``, while our CA certificate is on ``server_2``. We do not want any key material to leave each respective server.

.. code-block:: yaml+jinja

- name: Create private key for new certificate on server_1
community.crypto.openssl_privatekey:
path: /path/to/certificate.key
delegate_to: server_1
run_once: true

- name: Create certificate signing request (CSR) for new certificate
community.crypto.openssl_csr_pipe:
privatekey_path: /path/to/certificate.key
subject_alt_name:
- "DNS:ansible.com"
- "DNS:www.ansible.com"
- "DNS:docs.ansible.com"
delegate_to: server_1
run_once: true
register: csr

- name: Sign certificate with our CA
community.crypto.x509_certificate_pipe:
csr_content: "{{ ca_csr.csr }}"
provider: ownca
ownca_path: /path/to/ca-certificate.pem
ownca_privatekey_path: /path/to/ca-certificate.key
ownca_privatekey_passphrase: "{{ secret_ca_passphrase }}"
ownca_not_after: +365d # valid for one year
ownca_not_before: "-1d" # valid since yesterday
delegate_to: server_2
run_once: true
register: certificate

- name: Write certificate file on server_1
copy:
dest: /path/to/certificate.pem
content: "{{ certificate.certificate }}"
delegate_to: server_1
run_once: true

Please note that the above procedure is **not idempotent**. The following extended example reads the existing certificate from ``server_1`` (if exists) and provides it to the :ref:`community.crypto.x509_certificate_pipe module <ansible_collections.community.crypto.x509_certificate_pipe_module>`, and only writes the result back if it was changed:

.. code-block:: yaml+jinja

- name: Create private key for new certificate on server_1
community.crypto.openssl_privatekey:
path: /path/to/certificate.key
delegate_to: server_1
run_once: true

- name: Create certificate signing request (CSR) for new certificate
community.crypto.openssl_csr_pipe:
privatekey_path: /path/to/certificate.key
subject_alt_name:
- "DNS:ansible.com"
- "DNS:www.ansible.com"
- "DNS:docs.ansible.com"
delegate_to: server_1
run_once: true
register: csr

- name: Check whether certificate exists
stat:
path: /path/to/certificate.pem
delegate_to: server_1
run_once: true
register: certificate_exists

- name: Read existing certificate if exists
slurp:
src: /path/to/certificate.pem
when: certificate_exists.stat.exists
delegate_to: server_1
run_once: true
register: certificate

- name: Sign certificate with our CA
community.crypto.x509_certificate_pipe:
content: "{{ (certificate.content | b64decode) if certificate_exists.stat.exists else omit }}"
csr_content: "{{ ca_csr.csr }}"
provider: ownca
ownca_path: /path/to/ca-certificate.pem
ownca_privatekey_path: /path/to/ca-certificate.key
ownca_privatekey_passphrase: "{{ secret_ca_passphrase }}"
ownca_not_after: +365d # valid for one year
ownca_not_before: "-1d" # valid since yesterday
delegate_to: server_2
run_once: true
register: certificate

- name: Write certificate file on server_1
copy:
dest: /path/to/certificate.pem
content: "{{ certificate.certificate }}"
delegate_to: server_1
run_once: true
when: certificate is changed
60 changes: 60 additions & 0 deletions docs/docsite/rst/guide_selfsigned.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
.. _ansible_collections.community.crypto.docsite.guide_selfsigned:

How to create self-signed certificates
======================================

The `community.crypto collection <https://galaxy.ansible.com/community/crypto>`_ offers multiple modules that create private keys, certificate signing requests, and certificates. This guide shows how to create self-signed certificates.

For creating any kind of certificate, you always have to start with a private key. You can use the :ref:`community.crypto.openssl_privatekey module <ansible_collections.community.crypto.openssl_privatekey_module>` to create a private key. If you only specify ``path``, the default parameters will be used. This will result in a 4096 bit RSA private key:

.. code-block:: yaml+jinja

- name: Create private key (RSA, 4096 bits)
community.crypto.openssl_privatekey:
path: /path/to/certificate.key

You can specify ``type`` to select another key type, ``size`` to select a different key size (only available for RSA and DSA keys), or ``passphrase`` if you want to store the key password-protected:

.. code-block:: yaml+jinja

- name: Create private key (X25519) with password protection
community.crypto.openssl_privatekey:
path: /path/to/certificate.key
type: X25519
passphrase: changeme

To create a very simple self-signed certificate with no specific information, you can proceed directly with the :ref:`community.crypto.x509_certificate module <ansible_collections.community.crypto.x509_certificate_module>`:

.. code-block:: yaml+jinja

- name: Create simple self-signed certificate
community.crypto.x509_certificate:
path: /path/to/certificate.pem
privatekey_path: /path/to/certificate.key
provider: selfsigned

(If you used ``passphrase`` for the private key, you have to provide ``privatekey_passphrase``.)

You can use ``selfsigned_not_after`` to define when the certificate expires (default: in roughly 10 years), and ``selfsigned_not_before`` to define from when the certificate is valid (default: now).

To define further properties of the certificate, like the subject, Subject Alternative Names (SANs), key usages, name constraints, etc., you need to first create a Certificate Signing Request (CSR) and provide it to the :ref:`community.crypto.x509_certificate module <ansible_collections.community.crypto.x509_certificate_module>`. If you do not need the CSR file, you can use the :ref:`community.crypto.openssl_csr_pipe module <ansible_collections.community.crypto.openssl_csr_pipe_module>` as in the example below. (To store it to disk, use the :ref:`community.crypto.openssl_csr module <ansible_collections.community.crypto.openssl_csr_module>` instead.)

.. code-block:: yaml+jinja

- name: Create certificate signing request (CSR) for self-signed certificate
community.crypto.openssl_csr_pipe:
privatekey_path: /path/to/certificate.key
common_name: ansible.com
organization_name: Ansible, Inc.
subject_alt_name:
- "DNS:ansible.com"
- "DNS:www.ansible.com"
- "DNS:docs.ansible.com"
register: csr

- name: Create self-signed certificate from CSR
community.crypto.x509_certificate:
path: /path/to/certificate.pem
csr_content: "{{ csr.csr }}"
privatekey_path: /path/to/certificate.key
provider: selfsigned