Skip to content

F1rst-Unicorn/local-ca

 
 

Repository files navigation

local-ca

This role provides a local (i.e. on the node that executes ansible or on some delegated node) CA.

Warning: Commits after 0b2beb3015658c9f3fdeb9a1e92944d032b493ef use EasyRSA 3.x, which puts the configuration in a different location. Existing CAs will continue to work, but changing any of the CA parameters (unique_subject, kerberos_realm etc) will have no effect! You will need to manually upgrade your CAs (by extracting the template over them) to make use of the new configuration!

Configuration

Variable name Default value Description
local_ca_dhparam_size 2048 Size for generated Diffie-Hellman parameters
local_ca_workhost localhost The host to generate the CA on
local_ca_basepath undefined Base directories of CAs on the remote host if local_ca_workhost is defined
local_ca_fetchdir fetch/ctmp Where to store secret material on the control node
local_ca_owner root Owner of certificates on the target node
local_ca_group root Group of certificates on the target node
local_ca_mode 0640 Permissions of certificates on the target node
local_ca_unique_subject True Enforce unique CN names
local_ca_kerberos_realm EXAMPLE.ORG If generating Kerberos certificates, which realm are they for?
local_ca_expiry_days - How many days certificates should be valid before they expire (see below)
local_ca_skip_octal_check False Whether to allow file modes 416, 493, 488 and 420

local_ca_unique_subject

The value of the first execution of the role for a given CA is decisive. Subsequent runs with different value won't change the value of this configuration option. "Upgrading" an existing CA to allow non-unique names has to be done manually.

local_ca_kerberos_realm

This has the same update limitation as local_ca_unique_subject. If you're not using kerberos anyways, you can ignore this setting as it is only used for the kerberos-kdc and kerberos-client certificate types. The certificate is generated to the specification from the official documentation. For the moment, user certificates have to be generated manually on the server (certificate type kerberos-user).

local_ca_expiry_days

Define how many days different issued entities are valid. Example:

local_ca_expiry_days:
  ca: 10
  cert: 10
  cert_renew: 10
  crl: 10

ca controls validity of the root CA certificate. cert controls validity of issued server / client certificates issued by the CA. cert_renew controls how short before a certificate's expiry a new certificate for that entity may be issued. crl controls validity of Certificate Revokation Lists.

How to use this?

This role has to be called with parameters, like so:

  - role: local-ca
    local_ca_caname: DemoPKI
    <params>

where params consists of at least one of the following blocks:

  • local_ca_server: Generate a server certificate. Arguments:

    • cn (required): Common Name
    • c (optional): country code (2-letters)
    • st (optional): State/Province
    • city (optional): City/Locality
    • email (optional): Email addresses
    • ou (optional): Organisational Unit
    • org (optional): Organisation
    • san (optional): SAN in openssl cmdline format.
    • unique (optional): A CA-unique identifier to distinguish certificates with the same CN.
  • local_ca_both: Generate a server certificate that can also be used as a client certificate. Parameters are the same as local_ca_server.

  • local_ca_ca: Copy CA certificate to node

    • cert (required): destination for the PEM file
    • crl (optional): destination for CRL. The CRL gets regenerated each time this role is invoked.
  • local_ca_client: Generate a client certificate. Arguments:

    • cn (required): Common Name
    • c (optional): country code (2-letters)
    • st (optional): State/Province
    • city (optional): City/Locality
    • email (optional): Email addresses
    • ou (optional): Organisational Unit
    • org (optional): Organisation
    • unique (optional): A CA-unique identifier to distinguish certificates with the same CN.
  • local_ca_kdc: Generate a kerberos KDC certificate which includes the mandatory eku fields. Arguments:

    • cn (required): Common Name
  • local_ca_dhparam: Generate dhparam

    • dest (required): destination

Additionally you can specify formats for the three certificate-generating blocks (server, client and both). PEM files of the keys are always generated on the workhost. Supported formats are:

PEM

Just copy the generated PEM files to the node:

local_ca_server:
  ...
  pem:
    key: /path/to/key          # Optional
    cert: /path/to/cert        # Optional
    chain: /path/to/chain      # Optional. Cert with CA cert appended
    keychain: /path/to/chain   # Optional. Cert with CA cert and key appended

PKCS8

Wrap the private key into a DER PKCS8 container. To achieve this specify

local_ca_server:
  ...
  pkcs8:
    password: changeme          # optional. If missing, key is not encrypted
    path: /path/on/target/node

PKCS12

Wrap private key, certificate and CA certificate into a PKCS12 container. To achieve this specify:

local_ca_server:
  ...
  pkcs12:
    password: changeme
    name: my-key                # name of the keypair inside the container
    path: /path/on/target/node

Java Key Store

Wrap private key, certificate and CA certificate into an JKS container. To achieve this specify:

local_ca_server:
  ...
  jks:
    password: changeme          # DEPRECATED: Use storepassword instead
    storepassword: changeme
    name: my-key                # name of the keypair inside the container
    path: /path/on/target/node
    keypassword: changeme       # optional. If missing, key is not encrypted

An example invocation might look like this:

  - hosts: mon_server
    roles:
      - role: local-ca
        local_ca_caname: icinga
        local_ca_group: nagios
        local_ca_both:
          cn: "{{ ansible_fqdn }}"
          san: "DNS:{{ ansible_nodename }},DNS:{{ ansible_fqdn }},IP:{{ansible_all_ipv4_addresses|join(',IP:')}},IP:127.0.0.1"
          pkcs8:
            path: "/var/lib/icinga2/certs/{{ ansible_fqdn }}.der"
          pem:
            cert: "/var/lib/icinga2/certs/{{ ansible_fqdn }}.crt"
        local_ca_ca:
          cert: "/var/lib/icinga2/certs/ca.crt"

which would upload the CA and generate a dual-use certificate with both the unqualified and the fully qualified hostname and all IPv4s included.

Rationale

Why do you need this?

Because for some applications (redis+haproxy / kubernetes / icinga) you need your own CA, because:

  • Nodes need client certificates
  • The service you use makes excessive use of SNI (ex. one entry for every IP)
  • The service you use requires local domains in the certs

All of these things rule out an existing, public CA.

Why not use Ansible Secrets?

Because I can't find a way to edit them at run time. If you know how to accomplish this, feel free to simply convert the tar files to secrets (thats why I tar up things in the first place).

License

GPLv3 except for ca.template, which simply contains EasyRSA v3 which in turn is released under the GPLv2.

About

Ansible role for a local CA

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Jinja 79.5%
  • Python 20.5%