Skip to content

Commit

Permalink
Convert docs to new stack.
Browse files Browse the repository at this point in the history
closes pulp#5054.
  • Loading branch information
ggainey committed Feb 19, 2024
1 parent b53f4bf commit c6eede7
Show file tree
Hide file tree
Showing 6 changed files with 571 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES/pulp_certguard/5054.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Converted docs to use new documentation-stack.
64 changes: 64 additions & 0 deletions pulp_certguard/staging_docs/admin/learn/reverse_proxy_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Reverse Proxy Config

The client certificate submitted terminates [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security) (TLS) at the reverse proxy. The reverse proxy must do two things to
correctly pass the client certificate to the `pulpcore-content` app.

1. Forward the client's TLS certificate as the `X-CLIENT-CERT`.
2. The `X-CLIENT-CERT` needs to be urlencoded.

## Nginx Config Example

To configure Nginx to accept a client cert, and have it forward the urlencoded cert:

1. Enable the checking of a client cert with the [ssl_verify_client directive](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_verify_client).

2. Configure the `X-CLIENT-CERT` header to be urlencoded and forwarded. To avoid a client
falsifying the header, first unset it. It forwards the [\$ssl_client_escaped_cert](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_escaped_cert) variable
which is the urlencoded client cert:

```
proxy_set_header X-CLIENT-CERT $ssl_client_escaped_cert;
```

## Apache 2.4.10+ Config Example

To configure Apache to accept a client cert, urlencode it, and forward it you will need to:

1. Enable the checking of a client cert with the [SSLVerifyClient directive](https://httpd.apache.org/docs/current/mod/mod_ssl.html#sslverifyclient).

2. Enable the client certificate to be available as an environment variable with:

```
SSLOptions +ExportCertData
```

3. Configure the `X-CLIENT-CERT` header to be urlencoded and forwarded. To avoid a client
falsifying the header, first unset it. Then use [mod_rewrite](https://httpd.apache.org/docs/current/mod/mod_rewrite.html) to urlencode the [SSL_CLIENT_CERT](https://httpd.apache.org/docs/2.4/mod/mod_ssl.html) environment variable as follows:

```
RequestHeader unset X-CLIENT-CERT
RequestHeader set X-CLIENT-CERT "expr=%{escape:%{SSL_CLIENT_CERT}s}"
```

## Apache \< 2.4.10 Config Example

Apache versions earlier than 2.4.10 are not able to urlencode the client certificate.
`pulp-certguard` tries to detect this situation and work anyway.

In this case, to configure Apache to accept a client cert and forward it you will need to:

1. Enable the checking of a client cert with the [SSLVerifyClient directive](https://httpd.apache.org/docs/current/mod/mod_ssl.html#sslverifyclient).

2. Enable the client certificate to be available as an environment variable with:

```
SSLOptions +ExportCertData
```

3. Configure the `X-CLIENT-CERT` header to be forwarded. To avoid a client falsifying the header,
first unset it, then forward the data in the [SSL_CLIENT_CERT](https://httpd.apache.org/docs/2.4/mod/mod_ssl.html) environment variable as follows:

```
RequestHeader unset X-CLIENT-CERT
RequestHeader set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s"
```
81 changes: 81 additions & 0 deletions pulp_certguard/staging_docs/user/learn/debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Debugging

`pulp-certguard` contains debug statements which show the raw, received value of the
`X-CLIENT-CERT` header. This can be very valuable when debugging where the problem is in the chain
of certificates from the:

```
client <--> reverse proxy <--> pulp-certguard
```

## Enabling Debugging

Debugging is most easily enabled by adding the following line to your settings file, which is
by default located at `/etc/pulp/settings.py`:

```
LOGGING = {"dynaconf_merge": True, "loggers": {'': {'handlers': ['console'], 'level': 'DEBUG'}}}
```

After restarting your server-side services and making a request that sets the `X-CLIENT-CERT`
header, you should see a log message for each request where pulp-certguard is receiving a
`X-CLIENT-CERT` header.

## Using Logging Info

If you make a request but do not see a log message, you could have one of the following problems:

1. Debug logging is not enabled or applied. Check your `LOGGING` config.
2. The client is not requesting content from a Distribution protected with `pulp-certguard`. Check
your `Distribution` configuration.
3. The reverse proxy isn't configured to pass along the `X-CLIENT-CERT` config correctly. Check
your reverse proxy config against the example configs documented on this site.

If you do see a log message, but it's still not working you could have one of the following
problems:

1. The client isn't submitting the client certificate correctly to the reverse proxy. Ensure the
client is submitting a certificate and key via TLS to the reverse proxy.
2. The reverse proxy configuration is not correct. Compare your reverse proxy config against the
example configs documented on this site.

## Checking Authorized URLs in RHSM Certificates

The `rct cat-crt` command is useful for printing the detailed contents of RHSM certificates. This
is typically provided by the `subscription-manager` rpm on Centos, Fedora, and RHEL systems.

Once installed you can show the contents of an RHSM cert like this example running on a
[test certificate](https://github.com/pulp/pulp-certguard/blob/master/pulp_certguard/tests/functional/artifacts/rhsm/v3/4260035510644027985.pem):

```
$ rct cat-cert 4260035510644027985.pem
+-------------------------------------------+
Entitlement Certificate
+-------------------------------------------+
Certificate:
Path: v3/4260035510644027985.pem
Version: 3.4
Serial: 4260035510644027985
Start Date: 2020-03-05 19:50:59+00:00
End Date: 2048-06-01 00:00:00+00:00
Pool ID: Not Available
Subject:
CN: d3c3ff52c107457dbd3a0c28a345754a
O: Default_Organization
Issuer:
C: US
CN: sat-6-6-qa-rhel7.windhelm.example.com
L: Raleigh
O: Katello
OU: SomeOrgUnit
ST: North Carolina
Authorized Content URLs:
/Default_Organization/Library/custom/foo/foo
```
98 changes: 98 additions & 0 deletions pulp_certguard/staging_docs/user/tutorials/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Overview

The `pulp_certguard` plugin for [pulpcore 3.0+](https://pypi.org/project/pulpcore/) can cause
Pulp to refuse to serve content, e.g. rpms, Ansible Collections, etc, unless clients present a
valid certificate when they fetch content.

## Example

Company Foo only wants to serve rpms to customers who have paid, and they use Pulp 3.0+ to store
rpms for their customers. When a customer pays through, e.g. June 30, 2023, Company Foo generates
the customer a certificate signed by the certificate authority of Company Foo with an expiration
date of June 30, 2023. Company Foo also does the following:

1. Creates either a X.509 or RHSM Cert Guard offered by this plugin, configured with the Certificate
Authority Certificate used to sign the customer certificates.
2. Configures one or more Pulp Distributions which serving rpm repositories to be protected by the
X.509 or RHSM Cert Guard they created.

## Example Usage

The presentation of the client certificate should be done using TLS so the client can prove it not
only has the certificate but also the key for that certificate. This TLS connection terminates at
the reverse proxy, e.g. Nginx or Apache, and the client certificate is then forwarded to the
`pulpcore-content` app for Authorization checking. The forwarded certificate is expected to be
delivered to `pulpcore-content` as a urlencoded version of the client certificate stored in the
`X-CLIENT-CERT` HTTP header. Here's a diagram of the call flow:

client \<-- TLS --> Nginx \<-- X-CLIENT-CERT header --> pulpcore-content

!!! note
The `X-CLIENT-CERT` header needs to be urlencoded because newline characters present in valid
client certificates are not allowed in headers.


## Authorization

Any client presenting an X.509 or RHSM based certificate at request time will be authorized if and
only if the client cert is unexpired and signed by stored Certificate Authority Certificate stored
on the Certguard when it was created.

This allows for a use case where multiple Certificate Authority Certificates can be used to allow
some Pulp Distributions to be give access to some clients but not others depending on which CA Cert
signed the client certificate. While that is useful, it can become unwieldy to have to also manage
many CA Certificates. To resolve this an optional, additional authorization mechanism is available
where paths to Pulp Distributions are contained in the certificate itself.

## RHSM Certificate Path Based Authorization

!!! warning
At this time only the RHSM Cert Guard provides path based authorization.


RHSM Certificates allow for the embedding of Distribution.base_path within them. If they are present
in a client certificate, in addition to the authorization requirements from above, the client is
granted access if and only if the requested path is a subpath of a path contained in the client
certificate.

For example if the RHSM Certificate contains Authorized URL:

```
Authorized Content URLs:
/some/path/foo
```

Pulp would serve content from any protected Distribution with the following
`Distribution.base_path` values:

```
some
some/path
some/path/foo
```

Pulp would not serve content from a protected Distribution with the following
`Distribution.base_path` values:

```
another/path
some/path/bar
```

!!! note
The `pulpcore-content` app typically serves `Distribution.base_path` at a url starting with
`/pulp/content/`. When performing path checking only the `Distribution.base_path` portion of
the URL is checked.

`Distribution.base_bath` uses partial paths so it does *not* start with slash or end with one.
The Authorized URLs on the other hand do start with a slash. The RHSM path authorization check
code in `pulp-certguard` prepends a slash in front of the `Distribution.base_path`. This
allows a `Distribution.base_path` of `some/path` to become `/some/path` which would match
in RHSM against a certificate with either `/some` or `/some/path`.


## RHSM vs X.509 Cert Guards

pulp_certguard has two types of Cert Guards, the X509CertGuard and the RHSMCertGuard. Both are X.509
certificates, but the X509CertGuard can be made using common openssl tools, while RHSM Certificates
can only be made using [python-rhsm](https://pypi.org/project/rhsm/).
149 changes: 149 additions & 0 deletions pulp_certguard/staging_docs/user/tutorials/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Usage

To meaningfully use pulp-certguard you should already have a Pulp Distribution that requires
authorization and ideally it should have content in it. These examples assume you have a [pulp_file](site:/pulp_file/)
`FileRepository` with at least one `RepositoryVersion` with content in it. Also you'll need a `FileDistribution` serving that
`RepositoryVersion`.

The pulp-certguard examples should be straightforward to port to protect another distribution type.

### Create content to be protected

This step is about creating some data to test with. The significant thing for pulp-certguard is
having a repository to protect and having some content in that repository to test against.
```bash
echo "Creating FileRemote..."
pulp file remote create \
--name certguard-remote \
--url "https://fixtures.pulpproject.org/file/PULP_MANIFEST" \
--policy on_demand
echo "Creating FileRepository..."
pulp file repository create \
--name certguard-repository \
--remote certguard-remote \
--autopublish
echo "Sync repository..."
pulp file repository sync \
--name certguard-repository
echo "Distribute the respoitory's content..."
pulp file distribution create \
--name certguard-distribution \
--repository file:file:certguard-repository \
--base-path file/certguard-repository
```

## X509 CertGuard

### Create a content guard

This example assumes that `./ca.pem` is a PEM encoded Certificate Authority (CA) certificate. Each
X509 Content Guard needs a name so for this example we'll use `myguard`.

=== "Create X509 ContentGuard"

```bash
pulp content-guard x509 create \
--name my-509-guard \
--ca-certificate=@./ca.pem
```

=== "Create RHSM ContentGuard"

```bash
pulp content-guard rhsm create \
--name my-rhsm-guard \
--ca-certificate=@./ca.pem
```

=== "X509 Output"

```json
{
"pulp_href": "/pulp/api/v3/contentguards/certguard/x509/018dbdce-83c8-7602-ae8f-e8d5262d3cb8/",
"pulp_created": "2024-02-18T20:00:44.489636Z",
"name": "my-509-guard",
"description": null,
"ca_certificate": "-----BEGIN CERTIFICATE-----\n...-----END CERTIFICATE-----"
}
```

=== "RHSM Output"

```json
{
"pulp_href": "/pulp/api/v3/contentguards/certguard/rhsm/018dbddd-1894-7658-ab8f-1f33b544f2fc/",
"pulp_created": "2024-02-18T20:16:40.085402Z",
"name": "my-rhsm-guard",
"description": null,
"ca_certificate": "-----BEGIN CERTIFICATE-----\n...-----END CERTIFICATE-----"
}
```

### Protect the Distribution with the X509CertGuard

=== "Associate a ContentGuard to a Repository"

```bash
pulp file distribution update \
--name certguard-distribution \
--content-guard certguard:x509:my-509-guard
```

=== "Output"

```console
Started background task /pulp/api/v3/tasks/018dbdd6-ec6e-7cd9-a49d-1c1a2e55725f/
Done.
```

### Download `protected` content

#### X509 and RHSM Certguards

The following example assume the client will connect to the reverse proxy using TLS with the
following:

- The PEM encoded client certificate is stored at `~/client.pem` which is signed by the CA stored
on the X509CertGuard.
- The corresponding PEM encoded private key at `~/key.pem`.

It attempts to download the `1.iso` file from the FileDistribution at the path
`/pulp/content/somepath/` Note the `somepath` part of this is from the `base_url` of the
Distribution you are testing against.

For example with httpie you can submit the client cert and key via TLS using:

`$ http --cert ~/client.pem --cert-key ~/key.pem https://localhost/pulp/content/somepath/test.iso`

This is expected to yield binary data with a response like:

```console
HTTP/1.1 200 OK
Accept-Ranges: bytes
Connection: keep-alive
Content-Length: 3145728
Content-Type: application/octet-stream
Date: Tue, 21 Apr 2020 20:35:11 GMT
Last-Modified: Tue, 21 Apr 2020 19:23:06 GMT
Server: nginx/1.16.1



+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+
```

## RHSM-CertGuard-specific rules

!!! note
To use the `RHSMCertGuard` you have to manually install the [rhsm Python module](https://pypi.org/project/rhsm/) which provides RHSM certificate parsing on the pulp server.
It requires some system level dependencies, e.g. OpenSSL libraries, which are not the same on
all operating operating systems. `rhsm` from PyPI not being cross-distro is why this requires
manual installation.


If the RHSM client cert contains entitlement paths, **they must match the full path to the
Distribution** the client is fetching from. In this example that is `/pulp/content/somepath/`.


Loading

0 comments on commit c6eede7

Please sign in to comment.