Skip to content

Commit 83e684b

Browse files
committed
tuftool: add manual testing steps for FIPS tuf repos
Add instructions and resources for manually testing tuftool's FIPS feature to allow for easily repeatable testing. The instructions walk through creating a local TUF repo, serving the TUF repo via a Docker container, and downloading the repo via tuftool. Signed-off-by: Gavin Inglis <giinglis@amazon.com>
1 parent c0d27ad commit 83e684b

File tree

8 files changed

+358
-0
lines changed

8 files changed

+358
-0
lines changed

tuftool/fips-test/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Ignore artifacts created during test.
2+
test-fips-tough/
3+
test-keys/
4+
test-tuf-repo/

tuftool/fips-test/Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM public.ecr.aws/nginx/nginx:latest
2+
3+
RUN apt update && apt upgrade -y
4+
RUN mkdir -p /etc/pki/tls/certs
5+
RUN mkdir -p /etc/pki/tls/private

tuftool/fips-test/README.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Testing tough FIPS feature
2+
3+
The following are steps to take to test FIPS support with `tough` and `tuftool`. Steps will walk
4+
through creating a TUF repo, hosting the repo via Docker containers running nginx, and testing
5+
`tuftool download` against servers using FIPS and non-FIPS ciphers. Creation of the TUF repo
6+
relies on AWS KMS for signing.
7+
8+
## Install tuftool
9+
10+
```sh
11+
# From latest release
12+
$ cargo install --force tuftool --all-features
13+
```
14+
15+
```sh
16+
# From local changes
17+
$ cargo install --path ../../tuftool --all-features
18+
```
19+
20+
## Create TUF repo
21+
22+
```sh
23+
$ mkdir -p test-tuf-repo
24+
$ ./scripts/create-tuf-repo.sh
25+
```
26+
27+
This will create the repo under the "test-tuf-repo" directory.
28+
29+
## Create keys
30+
31+
```sh
32+
$ ./scripts/create-server-keys.sh
33+
```
34+
35+
Trust the generated server Certificate Authority on your host:
36+
37+
```sh
38+
sudo trust anchor --store ./test-keys/ca.crt
39+
```
40+
41+
## Build the tough-fips-testing container
42+
43+
```sh
44+
docker build . -t tough-fips-testing:latest
45+
```
46+
47+
## Run the server with FIPS
48+
49+
```sh
50+
docker run --rm -it -p 8080:443 \
51+
-v ./configs/nginx-fips.conf:/etc/nginx/nginx.conf \
52+
-v ./test-tuf-repo/out/metadata:/usr/share/nginx/html/metadata \
53+
-v ./test-tuf-repo/out/targets:/usr/share/nginx/html/targets \
54+
--mount type=bind,src=./test-keys/server.crt,dst=/etc/pki/tls/certs/domain.crt \
55+
--mount type=bind,src=./test-keys/server.key,dst=/etc/pki/tls/private/domain.key \
56+
tough-fips-testing:latest
57+
```
58+
59+
Test repo download:
60+
61+
```sh
62+
tuftool download -r ./test-tuf-repo/1.root.json \
63+
--targets-url https://localhost:8080/targets \
64+
--metadata-url https://localhost:8080/metadata \
65+
test-fips-tough
66+
```
67+
68+
Should succeed with:
69+
70+
```
71+
Downloading targets to "test-fips-tough"
72+
```
73+
74+
Clean up the downloaded repo:
75+
76+
```sh
77+
rm -rf test-fips-tough/
78+
```
79+
80+
**Stop the Docker container.**
81+
82+
## Run the server with non-FIPS ciphers
83+
84+
```sh
85+
docker run --rm -it -p 8080:443 \
86+
-v ./configs/nginx.conf:/etc/nginx/nginx.conf \
87+
-v ./test-tuf-repo/out/metadata:/usr/share/nginx/html/metadata \
88+
-v ./test-tuf-repo/out/targets:/usr/share/nginx/html/targets \
89+
--mount type=bind,src=./test-keys/server.crt,dst=/etc/pki/tls/certs/domain.crt \
90+
--mount type=bind,src=./test-keys/server.key,dst=/etc/pki/tls/private/domain.key \
91+
tough-fips-testing:latest
92+
```
93+
94+
Test repo download:
95+
96+
```sh
97+
tuftool download -r ./test-tuf-repo/1.root.json \
98+
--targets-url https://localhost:8080/targets \
99+
--metadata-url https://localhost:8080/metadata \
100+
test-fips-tough
101+
```
102+
103+
Expect failure:
104+
105+
```
106+
Failed to load repository: Failed to fetch https://localhost:8080/metadata/2.root.json: Transport 'other' error fetching 'https://localhost:8080/metadata/2.root.json': error sending request for url (https://localhost:8080/metadata/2.root.json)
107+
```
108+
109+
# Clean up
110+
111+
```
112+
rm -rf test-tuf-repo/
113+
rm -rf test-keys/
114+
rm -rf test-fips-tough/
115+
```

tuftool/fips-test/configs/csr.conf.in

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[ req ]
2+
default_bits = 2048
3+
prompt = no
4+
default_md = sha256
5+
distinguished_name = dn
6+
req_extensions = req_ext
7+
8+
[ dn ]
9+
C = US
10+
ST = WASHINGTON
11+
L = Seattle
12+
O = Bottlerocket
13+
OU = Bottlerocket Dev
14+
15+
[ req_ext ]
16+
subjectAltName = @alt_names
17+
18+
[ alt_names ]
19+
DNS.1 = localhost
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# For more information on configuration, see:
2+
# * Official English Documentation: http://nginx.org/en/docs/
3+
# * Official Russian Documentation: http://nginx.org/ru/docs/
4+
5+
user nginx;
6+
worker_processes auto;
7+
error_log /var/log/nginx/error.log debug;
8+
pid /run/nginx.pid;
9+
10+
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
11+
include /usr/share/nginx/modules/*.conf;
12+
13+
events {
14+
worker_connections 1024;
15+
}
16+
17+
http {
18+
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19+
'$status $body_bytes_sent "$http_referer" '
20+
'"$http_user_agent" "$http_x_forwarded_for"';
21+
22+
access_log /var/log/nginx/access.log main;
23+
24+
sendfile on;
25+
tcp_nopush on;
26+
keepalive_timeout 65;
27+
types_hash_max_size 4096;
28+
29+
include /etc/nginx/mime.types;
30+
default_type application/octet-stream;
31+
# Load modular configuration files from the /etc/nginx/conf.d directory.
32+
# See http://nginx.org/en/docs/ngx_core_module.html#include
33+
# for more information.
34+
include /etc/nginx/conf.d/*.conf;
35+
36+
server {
37+
listen 80;
38+
listen [::]:80;
39+
server_name localhost;
40+
root /usr/share/nginx/html;
41+
42+
# Load configuration files for the default server block.
43+
include /etc/nginx/default.d/*.conf;
44+
}
45+
46+
# Settings for a TLS enabled server.
47+
48+
server {
49+
listen 443 ssl;
50+
listen [::]:443 ssl;
51+
http2 on;
52+
server_name localhost;
53+
root /usr/share/nginx/html;
54+
55+
ssl_certificate "/etc/pki/tls/certs/domain.crt";
56+
ssl_certificate_key "/etc/pki/tls/private/domain.key";
57+
ssl_session_cache shared:SSL:1m;
58+
ssl_session_timeout 10m;
59+
60+
ssl_protocols TLSv1.2 TLSv1.3;
61+
62+
ssl_ciphers 'TLSv1.2+FIPS:kRSA+FIPS:!eNULL:!aNULL';
63+
64+
# Load configuration files for the default server block.
65+
include /etc/nginx/default.d/*.conf;
66+
67+
}
68+
69+
}

tuftool/fips-test/configs/nginx.conf

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# For more information on configuration, see:
2+
# * Official English Documentation: http://nginx.org/en/docs/
3+
# * Official Russian Documentation: http://nginx.org/ru/docs/
4+
5+
user nginx;
6+
worker_processes auto;
7+
error_log /var/log/nginx/error.log debug;
8+
pid /run/nginx.pid;
9+
10+
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
11+
include /usr/share/nginx/modules/*.conf;
12+
13+
events {
14+
worker_connections 1024;
15+
}
16+
17+
http {
18+
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19+
'$status $body_bytes_sent "$http_referer" '
20+
'"$http_user_agent" "$http_x_forwarded_for"';
21+
22+
access_log /var/log/nginx/access.log main;
23+
24+
sendfile on;
25+
tcp_nopush on;
26+
keepalive_timeout 65;
27+
types_hash_max_size 4096;
28+
29+
include /etc/nginx/mime.types;
30+
default_type application/octet-stream;
31+
# Load modular configuration files from the /etc/nginx/conf.d directory.
32+
# See http://nginx.org/en/docs/ngx_core_module.html#include
33+
# for more information.
34+
include /etc/nginx/conf.d/*.conf;
35+
36+
server {
37+
listen 80;
38+
listen [::]:80;
39+
server_name localhost;
40+
root /usr/share/nginx/html;
41+
42+
# Load configuration files for the default server block.
43+
include /etc/nginx/default.d/*.conf;
44+
}
45+
46+
# Settings for a TLS enabled server.
47+
48+
server {
49+
listen 443 ssl;
50+
listen [::]:443 ssl;
51+
http2 on;
52+
server_name localhost;
53+
root /usr/share/nginx/html;
54+
55+
ssl_certificate "/etc/pki/tls/certs/domain.crt";
56+
ssl_certificate_key "/etc/pki/tls/private/domain.key";
57+
ssl_session_cache shared:SSL:1m;
58+
ssl_session_timeout 10m;
59+
60+
ssl_protocols TLSv1.2 TLSv1.3;
61+
62+
ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256;
63+
64+
# Load configuration files for the default server block.
65+
include /etc/nginx/default.d/*.conf;
66+
67+
}
68+
69+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
3+
mkdir -p test-keys
4+
5+
openssl genrsa -out test-keys/server.key 2048
6+
openssl req -new -key test-keys/server.key -out test-keys/server.csr -config ./configs/csr.conf.in
7+
8+
# Generate CA certificate
9+
openssl genrsa -out test-keys/ca.key 2048 \
10+
&& openssl req -x509 -new -nodes -key test-keys/ca.key \
11+
-subj "/CN=bottlerocket/C=US/L=WASHINGTON" -days 1825 -out test-keys/ca.crt
12+
13+
openssl dhparam -out test-keys/dhparam.pem 2098
14+
15+
openssl x509 -req -in test-keys/server.csr -CA test-keys/ca.crt -CAkey test-keys/ca.key \
16+
-CAcreateserial -out test-keys/server.crt -days 10000 -extensions req_ext \
17+
-extfile ./configs/csr.conf.in
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/bash
2+
3+
create_new_kms_key(){
4+
alias="$1"
5+
if ! [[ "$alias" =~ ^alias/ ]]; then
6+
echo 'error: alias must start with "alias/"'
7+
exit 2
8+
fi
9+
10+
key_id="$(aws kms create-key --key-usage SIGN_VERIFY \
11+
--customer-master-key-spec RSA_3072 \
12+
--output json | jq -r .KeyMetadata.KeyId)"
13+
14+
aws kms create-alias --target-key-id "$key_id" --alias-name "$alias"
15+
}
16+
17+
ALIAS_SUFFIX=$(date "+%Y-%m-%d")
18+
TEST_TUF_REPO_PATH="./test-tuf-repo"
19+
20+
# Create RSA 3072 KMS keys
21+
create_new_kms_key "alias/bottlerocket-root-${ALIAS_SUFFIX}"
22+
create_new_kms_key "alias/bottlerocket-publication-${ALIAS_SUFFIX}"
23+
create_new_kms_key "alias/bottlerocket-timestamp-${ALIAS_SUFFIX}"
24+
25+
26+
tuftool root init --version 1 "${TEST_TUF_REPO_PATH}/1.root.json"
27+
28+
expiration_date=$(date -d "${ALIAS_SUFFIX} + 1 year" --iso-8601=date -u)T00:00:00+00:00
29+
30+
tuftool root expire "${TEST_TUF_REPO_PATH}/1.root.json" "${expiration_date}"
31+
32+
tuftool root set-threshold "${TEST_TUF_REPO_PATH}/1.root.json" root 1
33+
tuftool root set-threshold "${TEST_TUF_REPO_PATH}/1.root.json" snapshot 1
34+
tuftool root set-threshold "${TEST_TUF_REPO_PATH}/1.root.json" targets 1
35+
tuftool root set-threshold "${TEST_TUF_REPO_PATH}/1.root.json" timestamp 1
36+
37+
# Add keys
38+
tuftool root add-key "${TEST_TUF_REPO_PATH}/1.root.json" \
39+
-k "aws-kms://default/alias/bottlerocket-root-${ALIAS_SUFFIX}" \
40+
-r root
41+
42+
tuftool root add-key "${TEST_TUF_REPO_PATH}/1.root.json" \
43+
-k "aws-kms://default/alias/bottlerocket-publication-${ALIAS_SUFFIX}" \
44+
-r snapshot -r targets -r timestamp
45+
46+
tuftool root add-key "${TEST_TUF_REPO_PATH}/1.root.json" \
47+
-k "aws-kms://default/alias/bottlerocket-timestamp-${ALIAS_SUFFIX}" \
48+
-r timestamp
49+
50+
# Sign
51+
tuftool root sign "${TEST_TUF_REPO_PATH}/1.root.json" \
52+
-k "aws-kms://default/alias/bottlerocket-root-${ALIAS_SUFFIX}"
53+
54+
mkdir -p "${TEST_TUF_REPO_PATH}/empty"
55+
tuftool create \
56+
-t "${TEST_TUF_REPO_PATH}/empty" --outdir "${TEST_TUF_REPO_PATH}/out" --root "${TEST_TUF_REPO_PATH}/1.root.json" \
57+
-k "aws-kms://default/alias/bottlerocket-publication-${ALIAS_SUFFIX}" \
58+
--snapshot-expires 'in 7 days' --snapshot-version "$(date +%s)" \
59+
--targets-expires 'in 7 days' --targets-version "$(date +%s)" \
60+
--timestamp-expires 'in 7 days' --timestamp-version "$(date +%s)"

0 commit comments

Comments
 (0)