Skip to content

Commit

Permalink
9/12/24 - ritz303 : Edits to the README doc
Browse files Browse the repository at this point in the history
  • Loading branch information
agunn303 committed Sep 12, 2024
1 parent 9dfcb63 commit 0a45b9b
Showing 1 changed file with 182 additions and 169 deletions.
351 changes: 182 additions & 169 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,181 +1,192 @@
# RHTAS Ansible Collection
# Red Hat Trusted Artifact Signer Ansible collection

Automation to deploy the RHTAS ecosystem on RHEL
The purpose of this Ansible collection is to automate the deployment of the Red Hat Trusted Artifact Signer (RHTAS) service on Red Hat Enterprise Linux (RHEL).

:warning: **The contents of this repository are a Work in Progress.**
> [!IMPORTANT]
Deploying RHTAS by using Ansible is a Technology Preview feature only.
Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend to use them for production.
These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
See the support scope for [Red Hat Technology Preview](https://access.redhat.com/support/offerings/techpreview/) features for more details.

## Overview

The automation within this repository establishes the components of RHTAS, the downstream redistribution of [Sigstore project](https://sigstore.dev) within a single Red Hat Enterprise Linux (RHEL) machine using a standalone containerized deployment. Containers are spawned using Kubernetes based manifests using
[podman kube play](https://docs.podman.io/en/latest/markdown/podman-kube-play.1.html).
The RHTAS service is the downstream redistribution of the [Sigstore](https://sigstore.dev) project.
The automation contained within this Git repository installs and configures the components of RHTAS to run on a single RHEL server, which uses a standalone containerized deployment.
A Kubernetes-based manifest creates containers that uses [`podman kube play`](https://docs.podman.io/en/latest/markdown/podman-kube-play.1.html).

The following Sigstore components are deployed as part of this architecture:
The RHTAS Ansible collection deploys the following RHTAS components:

* [Rekor](https://docs.sigstore.dev/rekor/overview)
* [Trillian](https://github.com/google/trillian)
* Optionally a MariaDB instance and a Redis instance, although it is possible to use instances managed outside of Ansible
* [Trillian database](https://github.com/google/trillian)
* Optional: A self-managed MariaDB instance, and a Redis instance.
* [Fulcio](https://docs.sigstore.dev/fulcio/overview)
* [Certificate Log](https://docs.sigstore.dev/fulcio/certificate-issuing-overview)
* [Timestamp Authority](https://docs.sigstore.dev/verifying/timestamps/#timestamp-authorities)
* [TUF](https://theupdateframework.io/) server
* [The Update Framework (TUF) server](https://theupdateframework.io/)

An [NGINX](https://www.nginx.com) frontend is placed as an entrypoint to the various backend components. Communication is secured via a set of self-signed certificates that are generated at runtime.
An [NGINX](https://www.nginx.com) front end places an entrypoint to the various backend components.
A set of self-signed certificates get generated at runtime to establishing secure communications.

Utilize the steps below to understand how to setup and execute the provisioning.
This automation also deploys and configures a software load balancer as a central point of ingress.
The ingress host names are as follows, where `<base_hostname>` is your deployment's base hostname:

## Prerequisites

RHEL 9.2+ x86\_64 is supported to run the RHTAS components.

Ansible must be installed and configured on a control node that will be used to perform the automation.

Perform the following steps to prepare the control node for execution.

### Dependencies

Install the required Ansible collections by executing the following (this can be skipped if installing from Ansible Automation Hub, as `ansible-galaxy install` will install dependencies automatically).

```shell
ansible-galaxy collection install -r requirements.yml
```

### OIDC provider

An installation of an OIDC provider, such as [Keycloak](https://console.redhat.com/ansible/automation-hub/repo/published/redhat/sso/), must be provided to allow for integration with containerized RHTAS.

### Ingress

The automation deploys and configures a software load balancer as a central point of ingress. Multiple hostnames underneath a _base hostname_ are configured and include the following hostnames:

* https://rekor.<base_hostname>
* https://fulcio.<base_hostname>
* https://tsa.<base_hostname>
* https://tuf.<base_hostname>

Each of these hostnames must be configured in DNS to resolve to the target machine. The `base_hostname` parameter must be provided when executing the provisining. To configure hostnames in DNS, edit `/etc/hosts` with the following content:

```
<REMOTE_IP_ADDRESS> fulcio.<base_hostname> fulcio
<REMOTE_IP_ADDRESS> rekor.<base_hostname> rekor
<REMOTE_IP_ADDRESS> tsa.<base_hostname> tsa
<REMOTE_IP_ADDRESS> tuf.<base_hostname> tuf
```

### Cosign

[cosign](https://github.com/sigstore/cosign) is used as part of testing and validating the setup and configuration. It is an optional install if there is not a desire to perform the validation as described below.

## Provision

In order to deploy RHTAS on a RHEL 9.2+ VM:

1. Create an `inventory` file with a single VM in the `rhtas` group:
```
[rhtas]
123.123.123.123
```
2. Create a simple Ansible playbook `play.yml`:
```
- hosts: rhtas
vars:
base_hostname: TODO # e.g. example.com
# access credentials for registry.redhat.io (https://access.redhat.com/RegistryAuthentication)
tas_single_node_registry_username: TODO
tas_single_node_registry_password: TODO
tas_single_node_oidc_issuers:
- issuer: TODO # your OIDC provider (e.g. keycloak) URL
client_id: trusted-artifact-signer
url: TODO # your OIDC provider (e.g. keycloak) URL
type: email
tasks:
- name: Include TAS single node role
ansible.builtin.include_role:
name: redhat.artifact_signer.tas_single_node
vars:
ansible_become: true
```
3. Execute the following command if the collection is installed from Ansible Automation Hub:
```shell
ansible-playbook -i inventory play.yml
```
4. Execute the following command if you're running from the collection repository checked out locally:
```shell
ANSIBLE_ROLES_PATH="roles/" ansible-playbook -i inventory play.yml
```
### Add the root CA that was created to your local truststore.
The certificate can be downloaded from the browser Certificate Viewer by navigating to `https://rekor.<base_domain>`.
Download the _root_ certificate that issued the Rekor certificate.
In Red Hat based systems, the following commands will add a CA to the system truststore.
```shell
$ sudo openssl x509 -in ~/Downloads/root-cert-from-browser -out tas-ca.pem --outform PEM
$ sudo mv tas-ca.pem /etc/pki/ca-trust/source/anchors/
$ sudo update-ca-trust
```
## Signing a Container
* https://rekor.`<base_hostname>`
* https://fulcio.`<base_hostname>`
* https://tsa.`<base_hostname>`
* https://tuf.`<base_hostname>`

Utilize the following steps to sign a container that has been published to an OCI registry
1. Export the following environment variables substituting `BASE_HOSTNAME`, `KEYCLOAK_URL` and if necessary also `KEYCLOAK_REALM` with the values used as part of the provisioning:
```shell
export BASE_HOSTNAME="TODO-provide-base-hostname"
export KEYCLOAK_URL="TODO-your-keycloak-url"
export KEYCLOAK_REALM=trusted-artifact-signer
export TUF_URL=https://tuf.$BASE_HOSTNAME
export OIDC_ISSUER_URL=$KEYCLOAK_URL/auth/realms/$KEYCLOAK_REALM
export COSIGN_FULCIO_URL=https://fulcio.$BASE_HOSTNAME
export COSIGN_REKOR_URL=https://rekor.$BASE_HOSTNAME
export COSIGN_MIRROR=$TUF_URL
export COSIGN_ROOT=$TUF_URL/root.json
export COSIGN_OIDC_CLIENT_ID=$KEYCLOAK_REALM
export COSIGN_OIDC_ISSUER=$OIDC_ISSUER_URL
export COSIGN_CERTIFICATE_OIDC_ISSUER=$OIDC_ISSUER_URL
export COSIGN_YES="true"
export SIGSTORE_FULCIO_URL=$COSIGN_FULCIO_URL
export SIGSTORE_OIDC_ISSUER=$COSIGN_OIDC_ISSUER
export SIGSTORE_REKOR_URL=$COSIGN_REKOR_URL
export REKOR_REKOR_SERVER=$COSIGN_REKOR_URL
```
2. Initialize the TUF roots
```shell
cosign initialize
```
Note: If you have used `cosign` previously, you may need to delete the `~/.sigstore` directory
3. Sign the desired container
```shell
cosign sign -y <image>
```
Authenticate with the Keycloak instance using the desired credentials.
## Prerequisites

4. Verify the signed image
* RHEL x86\_64 9.2 or greater.
* Command-line access to the Ansible control node with a user that has `sudo` privileges.
* Update DNS records or `/etc/hosts` entries with the ingress host names and IP addresses.
* Installation and configuration of Ansible on a control node to perform the automation.
* Installation of the Ansible collections on the control node.
* If installing from the Ansible Automation Hub, then run `ansible-galaxy install redhat.artifact_signer`.
* If installing from this Git repository, then clone it locally, and run `ansible-galaxy collection install -r requirements.yml`.
* An OpenID Connect (OIDC) provider, such as [Keycloak](https://console.redhat.com/ansible/automation-hub/repo/published/redhat/sso/).
* The ability to resolve the ingress host names, by using the Domain Name System (DNS) or the `/etc/hosts` file.
* Optional:
Installation of the `podman` and [`cosign`](https://github.com/sigstore/cosign) binaries to verify that the RHTAS service is working as expected.

## Deploying

1. Create an `inventory` file with a single node under the `rhtas` group:

```
[rhtas]
123.123.123.123
```

2. Create an Ansible Playbook named `play.yml`, and replace `TODO` with your relevant information:

```yaml
- hosts: rhtas
vars:
base_hostname: TODO # e.g. example.com
# access credentials for registry.redhat.io (https://access.redhat.com/RegistryAuthentication)
tas_single_node_registry_username: TODO
tas_single_node_registry_password: TODO
tas_single_node_oidc_issuers:
- issuer: TODO # your OIDC provider (e.g. keycloak) URL
client_id: trusted-artifact-signer
url: TODO # your OIDC provider (e.g. keycloak) URL
type: email
tasks:
- name: Include TAS single node role
ansible.builtin.include_role:
name: redhat.artifact_signer.tas_single_node # Use if deploying from Ansible Automation Hub.
vars:
ansible_become: true
```
> [!NOTE]
If running this Playbook from a locally-cloned Git repository, then replace the `redhat.artifact_signer.tas_single_node` value with `tas_single_node`.

3. Install the RHTAS Ansible collection.

- If installing from Ansible Automation Hub, then run the following command:

```shell
ansible-playbook -i inventory play.yml
```

- If running from a locally-cloned Git repository, then run the following command:

```shell
export ANSIBLE_ROLES_PATH="roles/" ; ansible-playbook -i inventory play.yml
```

4. Add the root certificate authority (CA) to your local truststore:

```shell
sudo openssl x509 -in ~/Downloads/root-cert-from-browser -out tas-ca.pem --outform PEM
sudo mv tas-ca.pem /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
```
> [!TIP]
The certificate can be downloaded from the Certificate Viewer by navigating to `https://rekor.<base_hostname>` in a web browser.
Download the _root_ certificate that issued the Rekor certificate.

> [!NOTE]
Add this certificate to all RHTAS client nodes that use the `cosign` and `gitsign` binaries for signing and verifying artifacts.

## Verifying the deployment by signing a test container

1. Export the following environment variables, replacing `TODO` with your relevant information:

```shell
export BASE_HOSTNAME="TODO"
export KEYCLOAK_URL="TODO"
export KEYCLOAK_REALM=TODO
export TUF_URL=https://tuf.$BASE_HOSTNAME
export OIDC_ISSUER_URL=$KEYCLOAK_URL/auth/realms/$KEYCLOAK_REALM
export COSIGN_FULCIO_URL=https://fulcio.$BASE_HOSTNAME
export COSIGN_REKOR_URL=https://rekor.$BASE_HOSTNAME
export COSIGN_MIRROR=$TUF_URL
export COSIGN_ROOT=$TUF_URL/root.json
export COSIGN_OIDC_CLIENT_ID=$KEYCLOAK_REALM
export COSIGN_OIDC_ISSUER=$OIDC_ISSUER_URL
export COSIGN_CERTIFICATE_OIDC_ISSUER=$OIDC_ISSUER_URL
export COSIGN_YES="true"
export SIGSTORE_FULCIO_URL=$COSIGN_FULCIO_URL
export SIGSTORE_OIDC_ISSUER=$COSIGN_OIDC_ISSUER
export SIGSTORE_REKOR_URL=$COSIGN_REKOR_URL
export REKOR_REKOR_SERVER=$COSIGN_REKOR_URL
```

2. Initialize The Update Framework (TUF) system:

```shell
cosign initialize
```

> [!NOTE]
If you have used `cosign` before, you might need to delete the `~/.sigstore` directory first.

3. Sign a test container image.

a. Create an empty container image:

```shell
echo "FROM scratch" > ./tmp.Dockerfile
podman build . -f ./tmp.Dockerfile -t ttl.sh/rhtas/test-image:1h
```

b. Push the empty container image to the `ttl.sh` ephemeral registry:

```shell
podman push ttl.sh/rhtas/test-image:1h
```

c. Sign the container image:

```shell
cosign sign -y ttl.sh/rhtas/test-image:1h
```

A web browser opens allowing you to sign the container image with an email address.

d. Remove the temporary Docker file:

```shell
rm ./tmp.Dockerfile
```

4. Verify the signed image by replacing `TODO` with the signer's email address:

```shell
cosign verify --certificate-identity=TODO ttl.sh/rhtas/test-image:1h
```

If the signature verification does not result in an error, then the deployment of RHTAS was successful!

Refer to this example that verifies an image signed with email identity `[email protected]` and issuer `https://github.com/login/oauth`.
```shell
cosign verify \
--certificate-identity-regexp sigstore-user \
--certificate-oidc-issuer-regexp keycloak \
<image>
```
If the signature verification did not result in an error, the deployment of RHTAS was successful!

## Contributing

### Testing locally

This repository contains GitHub actions that will test PRs that come in with `ansible-lint` and `sanity-test` to enforce good code quality and practices.
This Git repository has GitHub actions that tests incoming PRs with `ansible-lint` and `sanity-test` to enforce good code quality and practices.

To run `ansible-lint` locally:

Expand All @@ -188,25 +199,27 @@ ansible-lint

To run `sanity-test` locally:

The `ansible-test` command relies on a specific directory structure for collections to function correctly. This structure follows the format:
`{...}/ansible_collections/{namespace}/{collection}/`
The `ansible-test` command relies on a specific directory structure for collections to function correctly.
This structure follows the format, `{...}/ansible_collections/{namespace}/{collection}/`.

To enable testing, make sure your local machine adheres to this format, which you can achieve by copying, symlinking, moving or cloning a repo into this structure.
`namespace` and `collection` names are not critical, as long as the overall format is kept, and no illegal characters are used such as `-`.
The `collection` refers to the current repository `artifact-signer-ansible`, while the namespace can be anything you want.
To enable testing, make sure your local machine adheres to this format, which you can achieve by copying, symlinking, moving or cloning a Git repository into this structure.
By keeping the overall format, and not using invalid characters, such as `-`, the `namespace` and `collection` names are not critical.
The `collection` refers to the current repository `artifact-signer-ansible`, while the `namespace` can be anything you want.

A valid path for our collection would be:
`{...}/ansible_collections/redhat/artifact_signer_ansible/`
A valid path for our collection would be, `{...}/ansible_collections/redhat/artifact_signer_ansible/`.

When this is achieved, you can run sanity checks by executing
To achieve this, you can run sanity checks by running the following:

`ansible-test sanity`
```shell
ansible-test sanity
```

### Testing Deployment on a VM
### Testing Deployment on a virtual machine

The [molecule/README.md](molecule/README.md) file contains instructions on testing the deployment on a VM. By default, [testing-farm](https://docs.testing-farm.io/) is used as the VM provider.
The [molecule/README.md](molecule/README.md) file has instructions on testing the deployment on a virtual machine (VM).
By default, the VM provider is [testing-farm.io](https://docs.testing-farm.io/).

## Feedback

Any and all feedback is welcome. Submit an [Issue](https://github.com/securesign/artifact-signer-ansible/issues) or [Pull Request](https://github.com/securesign/artifact-signer-ansible/pulls) as desired.
Any and all feedback is welcome.
Submit an [Issue](https://github.com/securesign/artifact-signer-ansible/issues) or [Pull Request](https://github.com/securesign/artifact-signer-ansible/pulls) as needed.

0 comments on commit 0a45b9b

Please sign in to comment.