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

feature: request ssh certificates #1

Merged
merged 8 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 18 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ trfore.smallstep Collection Release Notes

.. contents:: Topics

v1.1.0
======

Release Summary
---------------

New feature, request SSH certificates from step CA.

Major Changes
-------------

- Added SSH role for generating SSH certificates.

New Roles
---------

- trfore.smallstep.step_ssh - Request SSH Certificates from step CA Server

v1.0.0
======

Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
- This collection is for setting up a a public key infrastructure (PKI) using Smallstep. It will install CA server and, optionally, configure the CA server and host servers ("clients") to request x509 certificates from the CA.
- The default values for the collection are set with the intention of being used in production and **initializing the CA server offline, outside of an Ansible play**. However, you can set `step_ca_initialize: true` and initialize the PKI via an Ansible playbook, for more details see:
- [`step_ca` readme](roles/step_ca/README.md) or [scenario guide: ca](https://trfore.github.io/ansible-smallstep/branch/main/docsite/guide_ca_nonproduction.html)
- For client servers, the default argument values for the roles are designed for generating a single ACME certificate and automatically renewing it on each host. Yet, you can configure the roles to generate and request **SSH certificates** as well. See the example playbook below, READMEs and scenario guides for more details:
- [`step_cert` readme](roles/step_cert/README.md) or [scenario guide: client](https://trfore.github.io/ansible-smallstep/branch/main/docsite/guide_client.html)
-
- [`step_ssh` readme](roles/step_ssh/README.md) or [scenario guide: ssh](https://trfore.github.io/ansible-smallstep/branch/main/docsite/guide_ssh.html)
- Additionally, you can request multiple certificates, using different provisioners, for a single server. See [`step_provisioner`](roles/step_provisioner/README.md) for details.

## Install the Collection

Expand All @@ -23,6 +28,7 @@ ansible-galaxy collection install trfore.smallstep
- [`step_cert`](roles/step_cert/README.md) - Request an x509 certificate from the CA and automatically renew it
- [`step_cli`](roles/step_cli/README.md) - Install Step CLI
- [`step_provisioner`](roles/step_provisioner/README.md) - Add provisioners to Step CA
- [`step_ssh`](roles/step_ssh/README.md) - Generate SSH host certificate and configure server to accept user certificates

## Tested Platforms

Expand Down Expand Up @@ -147,6 +153,13 @@ ansible-galaxy collection install trfore.smallstep

- name: Request x509 Certificate
role: trfore.smallstep.step_cert

# For SSH certificates
- name: Configure Host for SSH Certificates
role: trfore.smallstep.step_ssh
vars:
step_ssh_provisioner: "Example.com" # JWK provisioner name extracted from 'Example.com CA'
step_ssh_provisioner_password: "password02" # Same value passed to 'step_provisioner_password', see 'step_ssh' README for details.
```

## Author and License Information
Expand Down
14 changes: 14 additions & 0 deletions changelogs/changelog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,17 @@ releases:
name: step_provisioner
namespace: null
release_date: "2024-04-01"
1.1.0:
changes:
major_changes:
- Added support for CentOS 8 and Debian 10-12.
- Added SSH role for generating SSH certificates.
release_summary: New feature, request SSH certificates from step CA.
fragments:
- release_v1.1.0.yml
objects:
role:
- description: Request SSH Certificates from step CA Server
name: step_ssh
namespace: null
release_date: "2024-04-01"
1 change: 1 addition & 0 deletions docs/docsite/extra-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ sections:
toctree:
- guide_ca_nonproduction
- guide_client
- guide_ssh
1 change: 1 addition & 0 deletions docs/docsite/rst/guide_ca_nonproduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ Additional Guides and References
--------------------------------

- :ref:`ansible_collections.trfore.smallstep.docsite.guide_client`
- :ref:`ansible_collections.trfore.smallstep.docsite.guide_ssh`
- `GitHub: Example playbooks and group_vars </~https://github.com/trfore/ansible-smallstep/blob/main/playbooks/>`_

.. _ansible_collections.trfore.smallstep.docsite.guide_ca_nonproduction.oauth2:
Expand Down
1 change: 1 addition & 0 deletions docs/docsite/rst/guide_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,5 @@ Additional Guides and References
--------------------------------

- :ref:`ansible_collections.trfore.smallstep.docsite.guide_ca_nonproduction`
- :ref:`ansible_collections.trfore.smallstep.docsite.guide_ssh`
- `GitHub: Example playbooks and group_vars </~https://github.com/trfore/ansible-smallstep/blob/main/playbooks/>`_
181 changes: 181 additions & 0 deletions docs/docsite/rst/guide_ssh.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
.. _ansible_collections.trfore.smallstep.docsite.guide_ssh:

Setup Servers and User Machines to Use SSH Certificates
=======================================================

- This guide will demonstrate how to setup a server and client machine to use SSH certificates to authenticate remote connections. It assumes the following:

- A CA is already configured to issue SSH certificates, and has a JWK, OIDC and SSHPOP provider configured. For instructions see: :ref:`ansible_collections.trfore.smallstep.docsite.guide_ca_nonproduction.ssh`.
- The root CA certificate fingerprint is known, i.e. on the CA server run ``step certificate fingerprint /etc/step-ca/certs/root_ca.crt``.

- Both the server and user machine will need to trust the central CA server then request:

- A **host** certificate for server.
- A **user** certificate for the user machine.

- Currently, the ``step_ssh`` role supports request authentication using the JWK provisioner for **host** certificates. And its recommended to use an **OIDC** provisioner for **user certs** (see below).

Configure Servers to Use SSH Certificates
-----------------------------------------

- To configure a server to use SSH certificate the following playbook will:

- Use the default JWK provider to request a SSH host certificate.
- Use the SSHPOP provider for SSH host certificate renewal.

- This is a minimal playbook that demonstrates the server using SSH certificates without requesting x509 certs. To also request x509 certs see: `non-production.yml (link) </~https://github.com/trfore/ansible-smallstep/blob/main/playbooks/non-production.yml>`_.

Playbook
^^^^^^^^

.. code-block:: yaml+jinja

- name: Setup Step CA Clients (Servers)
hosts: ca_clients
become: true
gather_facts: true
roles:
- name: Add Step CA Root Certificate to Trust Store
role: trfore.smallstep.step_ca_cert
vars:
step_ca_fingerprint: "CA_FINGERPRINT"
step_ca_url: "CA_URL" # https://ca.example.com

- name: Configure Host for SSH Certificates
role: trfore.smallstep.step_ssh
vars:
step_ssh_provisioner: "Example.com" # JWK provisioner
step_ssh_provisioner_password: "password02" # JWK provisioner password

Step CA Directory Layout
^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: shell

/etc/step-ca/
|-- certs
| |-- root_ca.crt
| `-- ssh_user_key.pub
`-- config
`-- defaults.json


Configure User Machine for SSH User Certificate
-----------------------------------------------

- This section assumes the following:

- User is a authorized on the server and their ``USERNAME`` matches one of the principals in the SSH certificate, see below: :ref:`ansible_collections.trfore.smallstep.docsite.guide_ssh.oidc`.

- To configure a user machine to use SSH certificate do the following:

1. Download and Add CA Certificate to Trust Store
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Bootstrap the machine to download root CA certificate and create a step configuration file at ``/home/USER/.step``.

.. code-block:: shell

# download root CA cert and create step configuration
$ step ca bootstrap --ca-url [CA_URL] --fingerprint [CA_FINGERPRINT]
# add root CA cert to trust store, e.g. /etc/ssl/certs
$ step certificate install $(step path)/certs/root_ca.crt

2. Request SSH User Certificate
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Request a user certificate using a OIDC (recommended) or JWK provisioner:

- For OIDC, the user will be redirected to the OAuth2 identity provider.
- For a JWK provisioner, the user will need a token. Note: The default JWK token should only be used in testing, as it provides full access to the CA. Additionally, providing short-lived encrypted single-use tokens is beyond the scope of the role and collection.

.. code-block:: shell

# OIDC
$ step ssh login USERNAME@example.com --provisioner "google"
# JWK
$ step ssh login USERNAME --provisioner "JWK_NAME"

3. Configure User's SSH client
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: shell

$ step ssh config

4. Test the Connection
^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: shell

$ ssh USERNAME@server01.example.com

- Optional, add SSH options and host server ``USERNAME`` to ``~/.ssh/config``.

.. code-block:: shell

Host server01.example.com
User USERNAME
ControlMaster auto
ControlPath ~/.ssh/control-%r@%h:%p
ControlPersist 15s

Directory Layout
^^^^^^^^^^^^^^^^

- Step Directory

.. code-block:: shell

/home/USER/.step/
├── certs
│   └── root_ca.crt
├── config
│   └── defaults.json
└── ssh
├── config
├── includes
└── known_hosts

- Also creates the following files:

- ``/usr/local/share/ca-certificates/Example_Root_CA_*.crt``
- ``/etc/ssl/certs/Example_Root_CA_*.pem``

Principals
----------

.. _ansible_collections.trfore.smallstep.docsite.guide_ssh.oidc:

OIDC Provisioner: Email Addresses With Special Characters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- If an email contains periods, for example ``jordan.doe@example.com``. Step will create multiple principles from the email address - ``jordandoe``, ``jordan.doe`` and ``jordan.doe@example.com``.
- Additionally the default ``USER`` will be ``jordandoe`` in ``~/.step/ssh/config``.

.. code-block:: shell

$ step ssh login jordan.doe@example.com --provisioner "google"
$ step ssh list --raw | grep jordan.doe@example.com | step ssh inspect
Type: ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate
...
Key ID: "jordan.doe@example.com"
...
Principals:
jordandoe
jordan.doe
jordan.doe@example.com

Additional Guides and References
--------------------------------

- :ref:`ansible_collections.trfore.smallstep.docsite.guide_ca_nonproduction`
- :ref:`ansible_collections.trfore.smallstep.docsite.guide_client`
- `GitHub: Example playbooks and group_vars </~https://github.com/trfore/ansible-smallstep/blob/main/playbooks/>`_

.. _ansible_collections.trfore.smallstep.docsite.guide_ssh.oauth2:

OAuth2 Credentials
^^^^^^^^^^^^^^^^^^

- `Google Workspace Docs: Create Access Credentials <https://developers.google.com/workspace/guides/create-credentials>`_
- `GitHub Docs: Authorizing OAuth apps <https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps>`_
- For a general list of OAuth provider configuration, see `OAuth2 Proxy Docs (link) <https://oauth2-proxy.github.io/oauth2-proxy/configuration/providers/>`_.
6 changes: 6 additions & 0 deletions extensions/molecule/step_ssh/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Molecule Scenario: step_ssh

- This scenario test the following roles:
- `step_cert`
- `step_provisioners`
- `step_ssh`
42 changes: 42 additions & 0 deletions extensions/molecule/step_ssh/converge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
- name: Initialize Hosts
hosts: all
tasks:
- name: Update APT cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 600
when: ansible_os_family == 'Debian'
changed_when: false
delay: 4
retries: 5

- name: Install Essential Packages for HTTPS
ansible.builtin.apt:
name:
- gnupg
- ca-certificates
- apt-transport-https
state: present
when: ansible_distribution == 'Debian'

- name: Setup OpenSSH
block:
- name: Install OpenSSH
ansible.builtin.package:
name:
- openssh-server
- "{{ 'openssh-clients' if ansible_os_family == 'RedHat' else 'openssh-client' }}"

- name: Generate an OpenSSH keypair
community.crypto.openssh_keypair:
path: /etc/ssh/ssh_host_ecdsa_key
type: ecdsa

- name: Deploy a Test CA Server and Host Client
ansible.builtin.import_playbook: ../../../playbooks/non-production-molecule.yml
vars:
step_ca_version: "{{ lookup('env', 'STEP_CA_VERSION') }}"
step_cli_version: "{{ lookup('env', 'STEP_CLI_VERSION') }}"
target_ca: "{{ lookup('env', 'TARGET_CA') }}"
target_clients: "{{ lookup('env', 'TARGET_CLIENTS') }}"
Loading
Loading