forked from pulp/pulpcore
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
closes pulp#5054.
- Loading branch information
Showing
6 changed files
with
571 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
64
pulp_certguard/staging_docs/admin/learn/reverse_proxy_config.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/`. | ||
|
||
|
Oops, something went wrong.