├── .github └── workflows │ ├── blank.yml │ └── book-deploy.yml ├── .gitignore ├── README.md ├── book.toml └── src ├── 01-prerequisites.md ├── 02-compute-resources.md ├── 03-domain-configuration.md ├── 04-rekor.md ├── 05-dex.md ├── 06-fulcio.md ├── 07-certifcate-transparency.md ├── 08-configure-registry.md ├── 09-cosign.md ├── 10-sign-container.md ├── README.md ├── SUMMARY.md ├── contributors.md ├── images ├── app-reg.png ├── ca_type.png ├── create.png ├── ecp384.png ├── enable_gcp_ca.png ├── glass.gif ├── label.png ├── oauth-consent.png ├── oauth-credentials.png ├── oauth-creds.png ├── oauth-redirect.png ├── rev.png ├── scopes.png ├── subj_name.png ├── user-email.png ├── view.png └── view_two.png └── misc └── contributors.md /.github/workflows/blank.yml: -------------------------------------------------------------------------------- 1 | name: Linter 2 | on: pull_request 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: xt0rted/markdownlint-problem-matcher@v1 9 | - name: "Run Markdown linter" 10 | uses: docker://avtodev/markdown-lint:v1 11 | with: 12 | args: src/*.md 13 | 14 | -------------------------------------------------------------------------------- /.github/workflows/book-deploy.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-20.04 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.ref }} 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Setup mdBook 18 | uses: peaceiris/actions-mdbook@v1 19 | with: 20 | mdbook-version: '0.4.10' 21 | # mdbook-version: 'latest' 22 | 23 | - run: mdbook build 24 | 25 | - name: Deploy 26 | uses: peaceiris/actions-gh-pages@v3 27 | if: ${{ github.ref == 'refs/heads/main' }} 28 | with: 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | publish_dir: ./book 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sigstore the hardway 2 | 3 | ![Publish Status](https://github.com/stacklok/sigstore-the-hard-way/workflows/publish/badge.svg) 4 | 5 | sigstore the hard way is hosted at and is available for free. 6 | 7 | 8 | ## contributing 9 | 10 | Should you wish to contribute, you're in the right place. 11 | 12 | Building the sigstore the hard way requires [mdBook]. 13 | 14 | [mdBook]: https://github.com/rust-lang-nursery/mdBook 15 | 16 | ```bash 17 | cargo install mdbook 18 | ``` 19 | 20 | Once installed you can use the `mdbook` command to view in realtime the sigstore-the-hardway documentation. 21 | 22 | ```bash 23 | mdbook serve --open 24 | ``` 25 | 26 | You do not need to build before making a pull request, we have a CI action that will automatically 27 | build the site and push it to the live site. 28 | 29 | Before you push, please test: 30 | 31 | To run the tests: 32 | 33 | ```bash 34 | mdbook test 35 | ``` 36 | 37 | ### Translations 38 | 39 | We'd love help translating the sigstore-the-hardway! See the [Translations] label to join in 40 | efforts. Open a new issue to start working on a new language! We're waiting on [mdbook support] for multiple languages 41 | before we merge any in, but feel free to start! 42 | 43 | [Translations]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3ATranslations 44 | [mdbook support]: https://github.com/rust-lang-nursery/mdBook/issues/5 45 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Luke Hinds"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "sigstore the hard way" 7 | description = "How to deploy sigstore from the ground up." 8 | default_theme = "Ayu" 9 | -------------------------------------------------------------------------------- /src/01-prerequisites.md: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | 3 | ## Google Cloud Platform 4 | 5 | ### Install the Google Cloud SDK 6 | 7 | Follow the Google Cloud SDK [documentation](https://cloud.google.com/sdk/) to install and configure the `gcloud` command line utility. 8 | 9 | Verify the Google Cloud SDK version is 338.0.0 or higher: 10 | 11 | ```bash 12 | gcloud version 13 | ``` 14 | 15 | ### Set a Default Compute Region and Zone 16 | 17 | This tutorial assumes a default compute region and zone have been configured. 18 | 19 | If you are using the `gcloud` command-line tool for the first time `init` is the easiest way to do this: 20 | 21 | ```bash 22 | gcloud init 23 | ``` 24 | 25 | `gcloud init` will give you an opportunity to create a new project and set a zone. If you're going to copy and paste CLI commands then for ease of use name it `sigstore-the-hard-way-proj` 26 | 27 | Be sure to authorize gcloud to access the Cloud Platform with your Google user credentials: 28 | 29 | ```bash 30 | gcloud auth login 31 | ``` 32 | 33 | Next set a default compute region and compute zone: 34 | 35 | ```bash 36 | gcloud config set compute/region europe-west1 37 | ``` 38 | 39 | Set a default compute zone: 40 | 41 | ```bash 42 | gcloud config set compute/zone europe-west1-b 43 | ``` 44 | 45 | > 📝 Use the `gcloud compute zones list` command to view additional regions and zones. 46 | -------------------------------------------------------------------------------- /src/02-compute-resources.md: -------------------------------------------------------------------------------- 1 | # Provisioning Compute / Network Resources 2 | 3 | ## Network Resources 4 | 5 | We next need to create a network for our compute resources: 6 | 7 | ```bash 8 | gcloud compute networks create sigstore-the-hard-way-proj --subnet-mode custom 9 | ``` 10 | 11 | > 📝 if you receive an `reason: UREQ_PROJECT_BILLING_NOT_FOUND` error, you need 12 | to [enable billing on the API](https://support.google.com/googleapi/answer/6158867?hl=en) 13 | 14 | We can now create a subnet with an internal range: 15 | 16 | ```bash 17 | gcloud compute networks subnets create sigstore \ 18 | --network sigstore-the-hard-way-proj \ 19 | --range 10.240.0.0/24 20 | ``` 21 | 22 | Create some firewall rules to allow tcp, udp and icmp protocols: 23 | 24 | ```bash 25 | gcloud compute firewall-rules create sigstore-the-hard-way-proj-allow-internal \ 26 | --allow tcp,udp,icmp \ 27 | --network sigstore-the-hard-way-proj \ 28 | --source-ranges 10.240.0.0/24 29 | ``` 30 | 31 | ```bash 32 | gcloud compute firewall-rules create sigstore-the-hard-way-allow-external \ 33 | --allow tcp:22,tcp:80,tcp:443,icmp \ 34 | --network sigstore-the-hard-way-proj \ 35 | --source-ranges 0.0.0.0/0 36 | ``` 37 | 38 | To verify the rules were created run the following command: 39 | 40 | ```bash 41 | gcloud compute firewall-rules list --filter="network:sigstore-the-hard-way-proj" 42 | ``` 43 | 44 | You should see an output similar to the following: 45 | 46 | ```bash 47 | NAME NETWORK DIRECTION PRIORITY ALLOW DENY DISABLED 48 | sigstore-the-hard-way-allow-external sigstore-the-hard-way-proj INGRESS 1000 tcp:22,tcp:80,tcp:443,icmp False 49 | sigstore-the-hard-way-proj-allow-internal sigstore-the-hard-way-proj INGRESS 1000 tcp,udp,icmp False 50 | ``` 51 | 52 | ## Compute Resources 53 | 54 | Now we need to create four compute nodes for each service. 55 | 56 | ```bash 57 | gcloud compute instances create sigstore-rekor \ 58 | --async \ 59 | --boot-disk-size 200GB \ 60 | --image-family debian-11 \ 61 | --image-project debian-cloud \ 62 | --machine-type e2-small \ 63 | --private-network-ip 10.240.0.10 \ 64 | --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \ 65 | --subnet sigstore \ 66 | --tags sigstore-the-hard-way-proj,sigstore-rekor 67 | ``` 68 | 69 | ```bash 70 | gcloud compute instances create sigstore-fulcio \ 71 | --async \ 72 | --boot-disk-size 200GB \ 73 | --image-family debian-11 \ 74 | --image-project debian-cloud \ 75 | --machine-type e2-small \ 76 | --private-network-ip 10.240.0.11 \ 77 | --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \ 78 | --subnet sigstore \ 79 | --tags sigstore-the-hard-way-proj,sigstore-fulcio 80 | ``` 81 | 82 | ```bash 83 | gcloud compute instances create sigstore-oauth2 \ 84 | --async \ 85 | --boot-disk-size 200GB \ 86 | --image-family debian-11 \ 87 | --image-project debian-cloud \ 88 | --machine-type e2-small \ 89 | --private-network-ip 10.240.0.12 \ 90 | --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \ 91 | --subnet sigstore \ 92 | --tags sigstore-the-hard-way-proj,sigstore-oauth2 93 | ``` 94 | 95 | ```bash 96 | gcloud compute instances create sigstore-ctl \ 97 | --async \ 98 | --boot-disk-size 200GB \ 99 | --image-family debian-11 \ 100 | --image-project debian-cloud \ 101 | --machine-type e2-small \ 102 | --private-network-ip 10.240.0.13 \ 103 | --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \ 104 | --subnet sigstore \ 105 | --tags sigstore-the-hard-way-proj,sigstore-ctl 106 | ``` 107 | 108 | Verify all compute instances are in a `RUNNING` state. 109 | 110 | ```bash 111 | gcloud compute instances list --filter="tags.items=sigstore-the-hard-way-proj" 112 | ``` 113 | 114 | The output should be as follows: 115 | 116 | ```bash 117 | NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS 118 | sigstore-ctl europe-west1-c e2-small 10.240.0.13 35.241.198.188 RUNNING 119 | sigstore-fulcio europe-west1-c e2-small 10.240.0.11 35.241.201.91 RUNNING 120 | sigstore-oauth2 europe-west1-c e2-small 10.240.0.12 35.240.60.139 RUNNING 121 | sigstore-rekor europe-west1-c e2-small 10.240.0.10 35.233.82.12 RUNNING 122 | ``` 123 | -------------------------------------------------------------------------------- /src/03-domain-configuration.md: -------------------------------------------------------------------------------- 1 | # Domain configuration 2 | 3 | Now that are instances are running, lets grab the external IP's and set up domains. 4 | 5 | > 📝 A cheap temp domain can be grabbed from [Google Cloud Domains](https://console.cloud.google.com/net-services/domains/). Just type in random, nonsensical string 6 | and you should easily be able to get a domain 7 | for $1. There are also lots of other providers. Use whatever works for you. 8 | 9 | ## Configuration 10 | 11 | Export a variable that will point to the domain you just bought. In this example we'll be using `example.com`: 12 | 13 | ```bash 14 | export DOMAIN="example.com" 15 | ``` 16 | 17 | We'll be using this variable throughout the following code-snippets. 18 | 19 | ### rekor.example.com 20 | 21 | Grab your external / public IP: 22 | 23 | ```bash 24 | Rekor_PIP=$(gcloud compute instances describe sigstore-rekor \ 25 | --format='get(networkInterfaces[0].accessConfigs[0].natIP)') 26 | ``` 27 | 28 | You now want to make an "A Record" to a subdomain or "rekor" and to your external IP from the above command 29 | 30 | To create resource records on Google: 31 | 32 | 1. Go to [Google Domains](https://domains.google.com/) 33 | 2. Click on your domain from the homepage 34 | 3. DNS > Manage Custom Records 35 | 36 | If you're using GCP as the DNS provider this can be done as follows: 37 | 38 | ```bash 39 | export ZONE="example-com" 40 | 41 | gcloud dns record-sets create rekor.$DOMAIN. \ 42 | --rrdatas=$Rekor_PIP \ 43 | --type=A --ttl=60 --zone=$ZONE 44 | ``` 45 | 46 | |Type|Host| Value| 47 | |---|---|---| 48 | | A Record|rekor|x.x.x.x| 49 | 50 | ### fulcio.example.com 51 | 52 | Now repeat the same for fulcio, and dex: 53 | 54 | ```bash 55 | Fulcio_PIP=$(gcloud compute instances describe sigstore-fulcio \ 56 | --format='get(networkInterfaces[0].accessConfigs[0].natIP)') 57 | ``` 58 | 59 | If you're using GCP as the DNS provider this can be done as follows: 60 | 61 | ```bash 62 | export ZONE="example-com" 63 | 64 | gcloud dns record-sets create fulcio.$DOMAIN. \ 65 | --rrdatas=$Fulcio_PIP \ 66 | --type=A --ttl=60 --zone=$ZONE 67 | ``` 68 | 69 | |Type|Host| Value| 70 | |---|---|---| 71 | | A Record|fulcio|x.x.x.x| 72 | 73 | ### oauth2.example.com 74 | 75 | ```bash 76 | oauth2_PIP=$(gcloud compute instances describe sigstore-oauth2 \ 77 | --format='get(networkInterfaces[0].accessConfigs[0].natIP)') 78 | ``` 79 | 80 | If you're using GCP as the DNS provider this can be done as follows: 81 | 82 | ```bash 83 | gcloud dns record-sets create oauth2.$DOMAIN. \ 84 | --rrdatas=$oauth2_PIP \ 85 | --type=A --ttl=60 --zone=$ZONE 86 | ``` 87 | 88 | |Type|Host| Value| 89 | |---|---|---| 90 | | A Record|oauth2|x.x.x.x| 91 | 92 | Check the records-sets generated during this process: 93 | 94 | ```bash 95 | gcloud dns record-sets list --zone $ZONE 96 | ``` 97 | 98 | > 📝 We do not need a domain for the certificate transparency log. This only 99 | communicate over a private network to Fulcio. 100 | -------------------------------------------------------------------------------- /src/04-rekor.md: -------------------------------------------------------------------------------- 1 | # rekor 2 | 3 | Rekor is sigstores signature transparency log. 4 | 5 | Rekor requires running instances of trillian's log server and signer, with a database backend. A few different databases 6 | can be used by trillian, for this example we will use mariadb. 7 | 8 | Let's start by logging in: 9 | 10 | ```bash 11 | gcloud compute ssh sigstore-rekor 12 | ``` 13 | 14 | ## Dependencies 15 | 16 | We need a few dependencies installed. 17 | 18 | Update your system: 19 | 20 | ```bash 21 | sudo apt-get update -y 22 | ``` 23 | 24 | If you want to save up some time, remove man-db first: 25 | 26 | ```bash 27 | sudo apt-get remove -y --purge man-db 28 | ``` 29 | 30 | Grab the following packages: 31 | 32 | ```bash 33 | sudo apt-get install mariadb-server git redis-server haproxy certbot -y 34 | ``` 35 | 36 | > 📝 redis-server is optional, but useful for a quick indexed search should you decide you need it. If you don't install it, 37 | you need to start rekor with `--enable_retrieve_api=false` 38 | 39 | ### Install latest golang compiler 40 | 41 | Download and run the golang installer (system package are often older than what rekor requires): 42 | 43 | ```bash 44 | curl -O https://storage.googleapis.com/golang/getgo/installer_linux 45 | ``` 46 | 47 | ```bash 48 | chmod +x installer_linux 49 | ``` 50 | 51 | ```bash 52 | ./installer_linux 53 | ``` 54 | 55 | e.g. 56 | 57 | ```bash 58 | Welcome to the Go installer! 59 | Downloading Go version go1.20.4 to /home/luke/.go 60 | This may take a bit of time... 61 | Downloaded! 62 | Setting up GOPATH 63 | GOPATH has been set up! 64 | 65 | One more thing! Run `source /home/$USER/.bash_profile` to persist the 66 | new environment variables to your current session, or open a 67 | new shell prompt. 68 | ``` 69 | 70 | As suggested run: 71 | 72 | ```bash 73 | source /home/$USER/.bash_profile 74 | 75 | go version 76 | go version go1.20.4 linux/amd64 77 | ``` 78 | 79 | ### Install rekor 80 | 81 | We will work with the rekor repo (we grab the whole repo as we will need a some scripts): 82 | 83 | ```bash 84 | mkdir -p ~/go/src/github.com/sigstore && cd "$_" 85 | ``` 86 | 87 | ```bash 88 | git clone https://github.com/sigstore/rekor.git && cd rekor/ 89 | ``` 90 | 91 | And let's install both the server and the CLI: 92 | 93 | ```bash 94 | go build -o rekor-cli ./cmd/rekor-cli 95 | ``` 96 | 97 | ```bash 98 | sudo cp rekor-cli /usr/local/bin/ 99 | ``` 100 | 101 | ```bash 102 | go build -o rekor-server ./cmd/rekor-server 103 | ``` 104 | 105 | ```bash 106 | sudo cp rekor-server /usr/local/bin/ 107 | ``` 108 | 109 | ### Database 110 | 111 | Trillian requires a database, let's first run `mysql_secure_installation` to 112 | remove test accounts etc: 113 | 114 | ```bash 115 | sudo mysql_secure_installation 116 | ``` 117 | 118 | The script is interactive. The following snippet captures the answers to 119 | the script's prompts: 120 | ```bash 121 | NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB 122 | SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! 123 | 124 | In order to log into MariaDB to secure it, we'll need the current 125 | password for the root user. If you've just installed MariaDB, and 126 | you haven't set the root password yet, the password will be blank, 127 | so you should just press enter here. 128 | 129 | Enter current password for root (enter for none): 130 | OK, successfully used password, moving on... 131 | 132 | Setting the root password ensures that nobody can log into the MariaDB 133 | root user without the proper authorization. 134 | 135 | Set root password? [Y/n] n 136 | ... skipping. 137 | 138 | By default, a MariaDB installation has an anonymous user, allowing anyone 139 | to log into MariaDB without having to have a user account created for 140 | them. This is intended only for testing, and to make the installation 141 | go a bit smoother. You should remove them before moving into a 142 | production environment. 143 | 144 | Remove anonymous users? [Y/n] Y 145 | ... Success! 146 | 147 | Normally, root should only be allowed to connect from 'localhost'. This 148 | ensures that someone cannot guess at the root password from the network. 149 | 150 | Disallow root login remotely? [Y/n] Y 151 | ... Success! 152 | 153 | By default, MariaDB comes with a database named 'test' that anyone can 154 | access. This is also intended only for testing, and should be removed 155 | before moving into a production environment. 156 | 157 | Remove test database and access to it? [Y/n] Y 158 | - Dropping test database... 159 | ... Success! 160 | - Removing privileges on test database... 161 | ... Success! 162 | 163 | Reloading the privilege tables will ensure that all changes made so far 164 | will take effect immediately. 165 | 166 | Reload privilege tables now? [Y/n] Y 167 | ... Success! 168 | 169 | Cleaning up... 170 | 171 | All done! If you've completed all of the above steps, your MariaDB 172 | installation should now be secure. 173 | 174 | Thanks for using MariaDB! 175 | ``` 176 | 177 | We can now build the database. 178 | 179 | Within the rekor repository is a `scripts/createdb.sh` script. 180 | 181 | Edit this script and populate the root password `ROOTPASS` you set for the system 182 | and then run the script (leave blank if not): 183 | 184 | ```bash 185 | cd scripts/ 186 | sudo ./createdb.sh 187 | Creating test database and test user account 188 | Loading table data.. 189 | ``` 190 | 191 | ### Install trillian components 192 | 193 | ```bash 194 | go install github.com/google/trillian/cmd/trillian_log_server@v1.3.14-0.20210713114448-df474653733c 195 | ``` 196 | 197 | ```bash 198 | sudo cp ~/go/bin/trillian_log_server /usr/local/bin/ 199 | ``` 200 | 201 | ```bash 202 | go install github.com/google/trillian/cmd/trillian_log_signer@v1.3.14-0.20210713114448-df474653733c 203 | ``` 204 | 205 | ```bash 206 | sudo cp ~/go/bin/trillian_log_signer /usr/local/bin/ 207 | ``` 208 | 209 | ### Run trillian 210 | 211 | The following are best run in two terminals, which are then left open (this 212 | helps for debugging): 213 | 214 | ```bash 215 | trillian_log_server -http_endpoint=localhost:8090 -rpc_endpoint=localhost:8091 --logtostderr ... 216 | ``` 217 | 218 | ```bash 219 | trillian_log_signer --logtostderr --force_master --http_endpoint=localhost:8190 -rpc_endpoint=localhost:8191 --batch_size=1000 --sequencer_guard_window=0 --sequencer_interval=200ms 220 | ``` 221 | 222 | Alternatively, create bare minimal systemd services: 223 | 224 | ```bash 225 | sudo bash -c 'cat << EOF > /etc/systemd/system/trillian_log_server.service 226 | [Unit] 227 | Description=trillian_log_server 228 | After=network-online.target 229 | Wants=network-online.target 230 | StartLimitIntervalSec=600 231 | StartLimitBurst=5 232 | 233 | [Service] 234 | ExecStart=/usr/local/bin/trillian_log_server -http_endpoint=localhost:8090 -rpc_endpoint=localhost:8091 --logtostderr ... 235 | Restart=on-failure 236 | RestartSec=5s 237 | 238 | [Install] 239 | WantedBy=multi-user.target 240 | EOF' 241 | ``` 242 | 243 | ```bash 244 | sudo bash -c 'cat << EOF > /etc/systemd/system/trillian_log_signer.service 245 | [Unit] 246 | Description=trillian_log_signer 247 | After=network-online.target 248 | Wants=network-online.target 249 | StartLimitIntervalSec=600 250 | StartLimitBurst=5 251 | 252 | [Service] 253 | ExecStart=/usr/local/bin/trillian_log_signer --logtostderr --force_master --http_endpoint=localhost:8190 -rpc_endpoint=localhost:8191 --batch_size=1000 --sequencer_guard_window=0 --sequencer_interval=200ms 254 | Restart=on-failure 255 | RestartSec=5s 256 | 257 | [Install] 258 | WantedBy=multi-user.target 259 | EOF' 260 | ``` 261 | 262 | Enable systemd services: 263 | 264 | ```bash 265 | sudo systemctl daemon-reload 266 | sudo systemctl enable trillian_log_server.service 267 | sudo systemctl enable trillian_log_signer.service 268 | sudo systemctl start trillian_log_server.service 269 | sudo systemctl start trillian_log_signer.service 270 | sudo systemctl status trillian_log_server.service 271 | sudo systemctl status trillian_log_signer.service 272 | ``` 273 | 274 | After the systemd services have been enabled, the output from the last command should be similar to: 275 | ```bash 276 | ● trillian_log_server.service - trillian_log_server 277 | Loaded: loaded (/etc/systemd/system/trillian_log_server.service; enabled; vendor preset: enabled) 278 | Active: active (running) since Thu 2021-09-30 17:41:49 UTC; 8s ago 279 | ● trillian_log_signer.service - trillian_log_signer 280 | Loaded: loaded (/etc/systemd/system/trillian_log_signer.service; enabled; vendor preset: enabled) 281 | Active: active (running) since Thu 2021-09-30 17:42:05 UTC; 12s ago 282 | ``` 283 | 284 | ### Start rekor 285 | 286 | Start rekor: 287 | 288 | ```bash 289 | rekor-server serve --rekor_server.address=0.0.0.0 --trillian_log_server.port=8091 290 | ``` 291 | 292 | Note: Rekor runs on port 3000 on all interfaces by default. 293 | 294 | Alternatively, you may create a bare minimal systemd service similar to trillian above: 295 | 296 | ```bash 297 | sudo bash -c 'cat << EOF > /etc/systemd/system/rekor.service 298 | [Unit] 299 | Description=rekor 300 | After=network-online.target 301 | Wants=network-online.target 302 | StartLimitIntervalSec=600 303 | StartLimitBurst=5 304 | 305 | [Service] 306 | ExecStart=/usr/local/bin/rekor-server serve --rekor_server.address=0.0.0.0 --trillian_log_server.port=8091 307 | Restart=on-failure 308 | RestartSec=5s 309 | 310 | [Install] 311 | WantedBy=multi-user.target 312 | EOF' 313 | ``` 314 | 315 | Enable systemd services: 316 | 317 | ```bash 318 | sudo systemctl daemon-reload 319 | sudo systemctl enable rekor.service 320 | sudo systemctl start rekor.service 321 | sudo systemctl status rekor.service 322 | ``` 323 | 324 | The last command should print: 325 | ```bash 326 | rekor.service - rekor 327 | Loaded: loaded (/etc/systemd/system/rekor.service; enabled; vendor preset: enabled) 328 | Active: active (running) since Mon 2023-05-08 11:09:20 UTC; 2h 0min ago 329 | Main PID: 21612 (rekor-server) 330 | Tasks: 8 (limit: 2353) 331 | Memory: 21.8M 332 | CPU: 649ms 333 | CGroup: /system.slice/rekor.service 334 | └─21612 /usr/local/bin/rekor-server serve --rekor_server.address=0.0.0.0 --trillian_log_server.port=8091 335 | ``` 336 | 337 | ### Let's encrypt (TLS) & HA Proxy config 338 | 339 | Let's create a HAProxy config, set `DOMAIN` to your registered domain and your 340 | private IP address: 341 | 342 | ```bash 343 | DOMAIN="rekor.example.com" 344 | IP="10.240.0.10" 345 | ``` 346 | 347 | Let's now run certbot to obtain our TLS certs: 348 | 349 | ```bash 350 | sudo certbot certonly --standalone --preferred-challenges http \ 351 | --http-01-address ${IP} --http-01-port 80 -d ${DOMAIN} \ 352 | --non-interactive --agree-tos --email youremail@domain.com 353 | ``` 354 | 355 | Move the PEM chain into place: 356 | 357 | ```bash 358 | sudo cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \ 359 | "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \ 360 | | sudo tee "/etc/ssl/private/${DOMAIN}.pem" > /dev/null 361 | ``` 362 | 363 | Now we need to change certbot configuration for automatic renewal. 364 | 365 | Prepare post renewal script: 366 | 367 | ```bash 368 | cat /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 369 | #!/bin/bash 370 | 371 | DOMAIN="rekor.example.com" 372 | 373 | cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \ 374 | "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \ 375 | > "/etc/ssl/private/${DOMAIN}.pem" 376 | 377 | systemctl reload haproxy.service 378 | ``` 379 | 380 | Make sure the script has executable flag set: 381 | 382 | ```bash 383 | sudo chmod +x /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 384 | ``` 385 | 386 | Replace port and address in the certbot's renewal configuration file for the domain (pass ACME request through the haproxy to certbot): 387 | 388 | ```bash 389 | sudo vim /etc/letsencrypt/renewal/rekor.example.com.conf 390 | ``` 391 | 392 | ```bash 393 | http01_port = 9080 394 | http01_address = 127.0.0.1 395 | ``` 396 | 397 | Append new line: 398 | 399 | ```bash 400 | post_hook = /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 401 | ``` 402 | 403 | Prepare haproxy configuration: 404 | 405 | ```bash 406 | cat > haproxy.cfg < /dev/null 97 | ``` 98 | 99 | Now we need to change certbot configuration for automatic renewal. 100 | 101 | Prepare post renewal script: 102 | 103 | ```bash 104 | cat /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 105 | #!/bin/bash 106 | 107 | DOMAIN="oauth2.example.com" 108 | 109 | cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \ 110 | "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \ 111 | > "/etc/ssl/private/${DOMAIN}.pem" 112 | 113 | systemctl reload haproxy.service 114 | ``` 115 | 116 | Make sure the script has executable flag set: 117 | 118 | ```bash 119 | sudo chmod +x /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 120 | ``` 121 | 122 | Replace port and address in the certbot's renewal configuration file for the domain (pass ACME request through the haproxy to certbot): 123 | 124 | ```bash 125 | sudo vim /etc/letsencrypt/renewal/oauth2.example.com.conf 126 | ``` 127 | 128 | ```bash 129 | http01_port = 9080 130 | http01_address = 127.0.0.1 131 | ``` 132 | 133 | Append new line 134 | 135 | ```bash 136 | post_hook = /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 137 | ``` 138 | 139 | Prepare haproxy configuration: 140 | 141 | ```bash 142 | cat > haproxy.cfg < 📝 We re using Google here, you can do the same for github and microsoft too. 240 | The placeholders are already within `config.yaml` 241 | 242 | 1. Head to the [credentials page](https://console.cloud.google.com/apis/credentials) 243 | 244 | 2. Select 'CONFIGURE CONSENT SCREEN' 245 | 246 | Select 'Internal' 247 | 248 | ![consent](images/oauth-consent.png) 249 | 250 | NOTE: If you're not a Google Workspace user, the 'Internal' option will not be available. You can only make your app available to external (general audience) users only. In such a case, the 'External' User Type works fine as well. 251 | 252 | Fill out the app registration details 253 | 254 | ![consent](images/app-reg.png) 255 | 256 | 3. Set scopes 257 | 258 | Select 'ADD OR REMOVE SCOPES' and set the `userinfo.email` scope 259 | 260 | ![scopes](images/scopes.png) 261 | 262 | Select "SAVE AND CONTINUE" 263 | 264 | Select "BACK TO DASHBOARD" and select 'Credentials' 265 | 266 | 4. Create OAuth Client ID 267 | 268 | ![credentials](images/oauth-credentials.png) 269 | 270 | Select "OAuth client ID". Select "Web Application" and fill out the "Authorized Redirect URIs" 271 | 272 | Select "CREATE" 273 | 274 | ![redirect-uri](images/oauth-redirect.png) 275 | 276 | 5. Note down tour Client ID and Secret and keep them safe (we will need them for dex) 277 | 278 | ### Configure Dex 279 | 280 | Set up the configuration file for dex. 281 | 282 | Provide saved OIDC details as variables: 283 | 284 | ```bash 285 | GOOGLE_CLIENT_ID="..." 286 | GOOGLE_CLIENT_SECRET="..." 287 | ``` 288 | 289 | ```bash 290 | cat > dex-config.yaml < /etc/systemd/system/dex.service 369 | [Unit] 370 | Description=dex 371 | After=network-online.target 372 | Wants=network-online.target 373 | StartLimitIntervalSec=600 374 | StartLimitBurst=5 375 | 376 | [Service] 377 | ExecStart=/usr/local/bin/dex serve --web-http-addr=0.0.0.0:6000 /etc/dex/dex-config.yaml 378 | Restart=on-failure 379 | RestartSec=5s 380 | 381 | [Install] 382 | WantedBy=multi-user.target 383 | EOF' 384 | ``` 385 | 386 | ```bash 387 | sudo systemctl daemon-reload 388 | sudo systemctl enable dex.service 389 | sudo systemctl start dex.service 390 | sudo systemctl status dex.service 391 | ``` 392 | -------------------------------------------------------------------------------- /src/06-fulcio.md: -------------------------------------------------------------------------------- 1 | # Fulcio 2 | 3 | Now it's time to install the Fulcio WebPKI. 4 | 5 | Fulcio requires a means to manage certificates. We have two options here, 6 | we can use a SoftHSM or Google Certificate Authority service. 7 | 8 | > 📝 As of time of writing, plans are in place to support AWS Cloud HSM and 9 | Azure Dedicated HSM. 10 | 11 | SSH into the Fulcio Compute instance 12 | 13 | ```bash 14 | gcloud compute ssh sigstore-fulcio 15 | ``` 16 | 17 | ## Dependencies 18 | 19 | We need a few dependencies installed 20 | 21 | Update your system 22 | 23 | ```bash 24 | sudo apt-get update -y 25 | ``` 26 | 27 | If you want to save up some time, remove man-db first 28 | 29 | ```bash 30 | sudo apt-get remove -y --purge man-db 31 | ``` 32 | 33 | Grab the following packages 34 | 35 | ```bash 36 | sudo apt-get install git gcc haproxy softhsm certbot opensc -y 37 | ``` 38 | 39 | > 📝 If you plan to use GCP Certificate Service, you can drop SoftHSM and opensc 40 | 41 | ### Install latest golang compiler 42 | 43 | Download and run the golang installer (system package are often older than what Fulcio requires): 44 | 45 | ```bash 46 | curl -O https://storage.googleapis.com/golang/getgo/installer_linux 47 | ``` 48 | 49 | ```bash 50 | chmod +x installer_linux 51 | ``` 52 | 53 | ```bash 54 | ./installer_linux 55 | ``` 56 | 57 | e.g. 58 | 59 | ``` 60 | Welcome to the Go installer! 61 | Downloading Go version go1.20.4 to /home/luke/.go 62 | This may take a bit of time... 63 | Downloaded! 64 | Setting up GOPATH 65 | GOPATH has been set up! 66 | 67 | One more thing! Run `source /home/$USER/.bash_profile` to persist the 68 | new environment variables to your current session, or open a 69 | new shell prompt. 70 | ``` 71 | 72 | As suggested run 73 | 74 | ```bash 75 | source /home/$USER/.bash_profile 76 | go version 77 | go version go1.20.4 linux/amd64 78 | ``` 79 | 80 | ### Install Fulcio 81 | 82 | ```bash 83 | go install github.com/sigstore/fulcio@v1.3.1 84 | ``` 85 | 86 | ```bash 87 | sudo cp ~/go/bin/fulcio /usr/local/bin/ 88 | ``` 89 | 90 | ### Let's encrypt (TLS) & HA Proxy config 91 | 92 | Let's create a HAProxy config, set `DOMAIN` to your registered domain and your 93 | private `IP` address 94 | 95 | ```bash 96 | DOMAIN="fulcio.example.com" 97 | IP="10.240.0.11" 98 | ``` 99 | 100 | Let's now run certbot to obtain our TLS certs. 101 | 102 | ```bash 103 | sudo certbot certonly --standalone --preferred-challenges http \ 104 | --http-01-address ${IP} --http-01-port 80 -d ${DOMAIN} \ 105 | --non-interactive --agree-tos --email youremail@domain.com 106 | ``` 107 | 108 | Move the PEM chain into place 109 | 110 | ```bash 111 | sudo cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \ 112 | "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \ 113 | | sudo tee "/etc/ssl/private/${DOMAIN}.pem" > /dev/null 114 | ``` 115 | 116 | Now we need to change certbot configuration for automatic renewal 117 | 118 | Prepare post renewal script 119 | 120 | ```bash 121 | cat /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 122 | #!/bin/bash 123 | 124 | DOMAIN="fulcio.example.com" 125 | 126 | cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \ 127 | "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \ 128 | > "/etc/ssl/private/${DOMAIN}.pem" 129 | 130 | systemctl reload haproxy.service 131 | ``` 132 | 133 | Make sure the script has executable flag set 134 | 135 | ```bash 136 | sudo chmod +x /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 137 | ``` 138 | 139 | Replace port and address in the certbot's renewal configuration file for the domain (pass ACME request through the haproxy to certbot) 140 | 141 | ```bash 142 | sudo vim /etc/letsencrypt/renewal/fulcio.example.com.conf 143 | ``` 144 | 145 | ``` 146 | http01_port = 9080 147 | http01_address = 127.0.0.1 148 | ``` 149 | 150 | Append new line 151 | 152 | ``` 153 | post_hook = /etc/letsencrypt/renewal-hooks/post/haproxy-ssl-renew.sh 154 | ``` 155 | 156 | Prepare haproxy configuration 157 | 158 | ```bash 159 | cat > haproxy.cfg < **Note** 256 | > You will need the file_ca_pub.pem file for the TUF root of cosign, with the sign-container section towards the end 257 | 258 | # SoftHSM Installation 259 | 260 | > By default SoftHSM stores tokens in `/var/lib/softhsm/tokens/` directory, which is defined 261 | in `/etc/softhsm/softhsm2.conf` configuration file, below we will define a custom configuration for fulcio. 262 | 263 | ```bash 264 | mkdir -p $HOME/fulcio-config/config 265 | mkdir $HOME/fulcio-config/tokens 266 | ``` 267 | 268 | ```bash 269 | cat < /dev/null 270 | directories.tokendir = $HOME/fulcio-config/tokens 271 | objectstore.backend = file 272 | log.level = INFO 273 | slots.removable = false 274 | EOF 275 | ``` 276 | 277 | ```bash 278 | export SOFTHSM2_CONF="$HOME/fulcio-config/config/softhsm2.cfg" 279 | ``` 280 | 281 | ```bash 282 | echo 'export SOFTHSM2_CONF="$HOME/fulcio-config/config/softhsm2.cfg"' >> ~/.bash_profile 283 | ``` 284 | 285 | ```bash 286 | softhsm2-util --init-token --slot 0 --label fulcio --pin 2324 --so-pin 2324 287 | ``` 288 | 289 | Tokens will now be generated in `fulcio-config\tokens` 290 | 291 | ```bash 292 | ls -la $HOME/fulcio-config/tokens 293 | ``` 294 | 295 | For example: 296 | 297 | ```bash 298 | softhsm2-util --init-token --slot 0 --label fulcio 299 | === SO PIN (4-255 characters) === 300 | Please enter SO PIN: **** 301 | Please reenter SO PIN: **** 302 | === User PIN (4-255 characters) === 303 | Please enter user PIN: **** 304 | Please reenter user PIN: ****** 305 | ERROR: The entered PINs are not equal. 306 | === User PIN (4-255 characters) === 307 | Please enter user PIN: **** 308 | Please reenter user PIN: **** 309 | The token has been initialized and is reassigned to slot 1773686385 310 | ``` 311 | 312 | Lets create a SoftHSM config for Fulcio 313 | 314 | ```bash 315 | cat < /dev/null 316 | { 317 | "Path" : "/usr/lib/softhsm/libsofthsm2.so", 318 | "TokenLabel": "fulcio", 319 | "Pin" : "2324" 320 | } 321 | EOF 322 | ``` 323 | 324 | > **Note** 325 | > The Path may vary for different OS versions. 326 | 327 | Now let's create a private key within the HSM 328 | 329 | ```bash 330 | pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --login-type user --keypairgen --id 1 --label PKCS11CA --key-type EC:secp384r1 331 | ``` 332 | 333 | For example: 334 | 335 | ```bash 336 | pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --login-type user --keypairgen --id 1 --label PKCS11CA --key-type EC:secp384r1 337 | Using slot 0 with a present token (0x69b84e71) 338 | Logging in to "fulcio". 339 | Please enter User PIN: 340 | Key pair generated: 341 | Private Key Object; EC 342 | label: PKCS11CA 343 | ID: 01 344 | Usage: decrypt, sign, unwrap, derive 345 | Access: sensitive, always sensitive, never extractable, local 346 | Public Key Object; EC EC_POINT 384 bits 347 | EC_POINT: 046104b04911577ad1a655ba469b32ae63832d6c0d19482058af1822c2b42f54934da3613cd87171594a9b00ff1f0b298c75fa9383470ec46f0b4a35e73b54c34cf2ecc664ada2d0a818a5ac2390d952cb3b8d66ebea974a1bb2465f323cbebc50927d 348 | EC_PARAMS: 06052b81040022 349 | label: PKCS11CA 350 | ID: 01 351 | Usage: encrypt, verify, wrap, derive 352 | Access: local 353 | ``` 354 | 355 | Now its time to create a Root CA using our newly minted private key: 356 | 357 | ```bash 358 | cd $HOME/fulcio-config/ 359 | fulcio createca --org={ORG} --country={UK} --locality={TOWN} --province={PROVINCE} --postal-code={POST_CODE} --street-address={STREET} --hsm-caroot-id 1 --out fulcio-root.pem 360 | ``` 361 | 362 | An example: 363 | 364 | ```bash 365 | cd $HOME/fulcio-config/ 366 | fulcio createca --org=acme --country=USA --locality=Anytown --province=AnyPlace --postal-code=ABCDEF --street-address=123 Main St --hsm-caroot-id 1 --out fulcio-root.pem 367 | 2021-10-01T18:09:16.284Z INFO app/createca.go:48 binding to PKCS11 HSM 368 | 2021-10-01T18:09:16.289Z INFO app/createca.go:68 finding slot for private key: PKCS11CA 369 | 2021-10-01T18:09:16.304Z INFO app/createca.go:108 Root CA: 370 | -----BEGIN CERTIFICATE----- 371 | MIICJDCCAaqgAwIBAgIIVUu5cbwBx8EwCgYIKoZIzj0EAwMwVjELMAkGA1UEBhMC 372 | TFYxCzAJBgNVBAgTAkxWMQswCQYDVQQHEwJMVjENMAsGA1UECRMESG9tZTEPMA0G 373 | A1UEERMGTFYxMDI2MQ0wCwYDVQQKEwRhY21lMB4XDTIxMTAwMTE4MDkxNloXDTMx 374 | MTAwMTE4MDkxNlowVjELMAkGA1UEBhMCTFYxCzAJBgNVBAgTAkxWMQswCQYDVQQH 375 | EwJMVjENMAsGA1UECRMESG9tZTEPMA0GA1UEERMGTFYxMDI2MQ0wCwYDVQQKEwRh 376 | Y21lMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEk4wYXHkLhdDlUlASZc65GI+5VDv3 377 | OqmFdOI7/TwnPfrqFBNCxTPp0qNh7//s55tRac5pkXV4Af+xWUETlRd6RqBKcjjX 378 | PHMZ0f+J/pZui4pPmw3ItvVCqfmNvCtASksSo0UwQzAOBgNVHQ8BAf8EBAMCAQYw 379 | EgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUOXQnhKM/yhGTICrrgO78QyVN 380 | nUMwCgYIKoZIzj0EAwMDaAAwZQIwEd1VjWI+P3eXMwUOGXbWJMYzrpcLakwj0JPW 381 | Bx6oFXBadm4jZoKQX1FfNXMWgu0mAjEA4nz6OBtF8YJGRS9bTnWfe4V/lwukRczk 382 | OPl9CeCgaJqQRXlMSw8uf3nO0rYXTGCF 383 | -----END CERTIFICATE----- 384 | 385 | 2021-10-01T18:09:16.324Z INFO app/createca.go:122 root CA created with PKCS11 ID: 1 386 | 2021-10-01T18:09:16.324Z INFO app/createca.go:138 root CA saved to file: fulcio-root.pem 387 | ``` 388 | 389 | Check Root CA key usage 390 | 391 | ```bash 392 | openssl x509 -in fulcio-root.pem -noout -ext extendedKeyUsage,keyUsage 393 | X509v3 Key Usage: critical 394 | Certificate Sign, CRL Sign 395 | ``` 396 | 397 | Transfer the root certificate over to the certificate transparency log (or copy / paste into a text file for later). 398 | 399 | ```bash 400 | gcloud compute scp fulcio-root.pem @sigstore-ctl:~/ 401 | ``` 402 | 403 | # Google Certificate Authority Service 404 | 405 | Navigate to the [Certificate Authority Service API](https://console.cloud.google.com/marketplace/product/google/privateca.googleapis.com) and enable the service 406 | 407 | ![Enable CA](images/enable_gcp_ca.png) 408 | 409 | On the Google Cloud Console page, go to Security > Certificate Authority Service > Create CA 410 | 411 | 1. Set the CA type (DevOps) 412 | 413 | ![CA Type](images/ca_type.png) 414 | 415 | 2. Set the cert subject details 416 | 417 | ![Subject](images/subj_name.png) 418 | 419 | 3. Set the key and algorithm to Ecliptic Curve P384 420 | 421 | ![ecp384](images/ecp384.png) 422 | 423 | 4. Leave Configure Artifacts as it is 424 | 425 | ![rev](images/rev.png) 426 | 427 | 5. Label (don't need one) 428 | 429 | ![label](images/label.png) 430 | 431 | 6. Create the CA 432 | 433 | ![Create CA](images/create.png) 434 | 435 | 7. Note down the Root CA and Resource name 436 | 437 | ![Overview A](images/view.png) 438 | 439 | ![Overview B](images/view_two.png) 440 | 441 | # Fulcio Config 442 | 443 | Set the DNS for the OAuth2 / Dex Server 444 | 445 | ```bash 446 | OAUTH2_DOMAIN="oauth2.example.com" 447 | ``` 448 | 449 | ```bash 450 | cat > $HOME/fulcio-config/config.json < 📝 Don't worry that the Certificate Transparency Log is not up yet. We will 529 | set this up next. 530 | 531 | ## Google Certificate Authority Service 532 | 533 | ```bash 534 | fulcio serve --ca googleca --gcp_private_ca_parent=${resource_name} --ct-log-url=http://sigstore-ctl:6105/sigstore --host=0.0.0.0 --port=5000 535 | ``` 536 | 537 | > 📝 Your resource name is a long POSIX type path string, e.g. `projects/sigstore-the-hard-way-proj/locations/europe-west1/caPools/sigstore-the-hard-way/certificateAuthorities/xxxx` 538 | 539 | For example 540 | 541 | ``` 542 | fulcio serve --ca googleca --gcp_private_ca_parent=projects/sigstore-the-hard-way-proj/locations/europe-west1/caPools/sigstore-the-hard-way/certificateAuthorities/xxxx --ctl-log-url=http://sigstore-ctl:6105/sigstore 543 | ``` 544 | -------------------------------------------------------------------------------- /src/07-certifcate-transparency.md: -------------------------------------------------------------------------------- 1 | # Certificate transparency log 2 | 3 | We will now install the Certificate transparency log (CTL). 4 | 5 | CTL requires running instances of trillian's log server and signer 6 | 7 | Let's start by logging in: 8 | 9 | ```bash 10 | gcloud compute ssh sigstore-ctl 11 | ``` 12 | 13 | ## Dependencies 14 | 15 | ```bash 16 | sudo apt-get update -y 17 | ``` 18 | 19 | If you want to save up some time, remove man-db first 20 | 21 | ```bash 22 | sudo apt-get remove -y --purge man-db 23 | ``` 24 | 25 | ```bash 26 | sudo apt-get install mariadb-server git wget -y 27 | ``` 28 | 29 | ### Install latest golang compiler 30 | 31 | Download and run the golang installer (system package are often older than what Trillian requires): 32 | 33 | ```bash 34 | curl -O https://storage.googleapis.com/golang/getgo/installer_linux 35 | ``` 36 | 37 | ```bash 38 | chmod +x installer_linux 39 | ``` 40 | 41 | ```bash 42 | ./installer_linux 43 | ``` 44 | 45 | e.g. 46 | 47 | ```bash 48 | Welcome to the Go installer! 49 | Downloading Go version go1.20.4 to /home/luke/.go 50 | This may take a bit of time... 51 | Downloaded! 52 | Setting up GOPATH 53 | GOPATH has been set up! 54 | 55 | One more thing! Run `source /home/$USER/.bash_profile` to persist the 56 | new environment variables to your current session, or open a 57 | new shell prompt. 58 | ``` 59 | 60 | As suggested run 61 | 62 | ```bash 63 | source /home/$USER/.bash_profile 64 | go version 65 | go version go1.20.4 linux/amd64 66 | ``` 67 | 68 | ### Database 69 | 70 | Trillian requires a database, let's first run `mysql_secure_installation` 71 | 72 | ```bash 73 | sudo mysql_secure_installation 74 | ``` 75 | 76 | The script is interactive. The following snippet captures the answers to 77 | the script's prompts: 78 | ```bash 79 | NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB 80 | SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! 81 | 82 | In order to log into MariaDB to secure it, we'll need the current 83 | password for the root user. If you've just installed MariaDB, and 84 | you haven't set the root password yet, the password will be blank, 85 | so you should just press enter here. 86 | 87 | Enter current password for root (enter for none): 88 | OK, successfully used password, moving on... 89 | 90 | Setting the root password ensures that nobody can log into the MariaDB 91 | root user without the proper authorisation. 92 | 93 | Set root password? [Y/n] n 94 | ... skipping. 95 | 96 | By default, a MariaDB installation has an anonymous user, allowing anyone 97 | to log into MariaDB without having to have a user account created for 98 | them. This is intended only for testing, and to make the installation 99 | go a bit smoother. You should remove them before moving into a 100 | production environment. 101 | 102 | Remove anonymous users? [Y/n] Y 103 | ... Success! 104 | 105 | Normally, root should only be allowed to connect from 'localhost'. This 106 | ensures that someone cannot guess at the root password from the network. 107 | 108 | Disallow root login remotely? [Y/n] Y 109 | ... Success! 110 | 111 | By default, MariaDB comes with a database named 'test' that anyone can 112 | access. This is also intended only for testing, and should be removed 113 | before moving into a production environment. 114 | 115 | Remove test database and access to it? [Y/n] Y 116 | - Dropping test database... 117 | ... Success! 118 | - Removing privileges on test database... 119 | ... Success! 120 | 121 | Reloading the privilege tables will ensure that all changes made so far 122 | will take effect immediately. 123 | 124 | Reload privilege tables now? [Y/n] Y 125 | ... Success! 126 | 127 | Cleaning up... 128 | 129 | All done! If you've completed all of the above steps, your MariaDB 130 | installation should now be secure. 131 | 132 | Thanks for using MariaDB! 133 | ``` 134 | 135 | We can now import the database as we used for rekor 136 | 137 | ```bash 138 | wget https://raw.githubusercontent.com/sigstore/rekor/main/scripts/createdb.sh 139 | ``` 140 | 141 | ```bash 142 | wget https://raw.githubusercontent.com/sigstore/rekor/main/scripts/storage.sql 143 | ``` 144 | 145 | ```bash 146 | chmod +x createdb.sh 147 | ``` 148 | 149 | ```bash 150 | sudo ./createdb.sh 151 | ``` 152 | 153 | E.g. 154 | 155 | ``` 156 | sudo ./createdb.sh 157 | Creating test database and test user account 158 | Loading table data.. 159 | ``` 160 | 161 | ### Install trillian components 162 | 163 | ```bash 164 | go install github.com/google/trillian/cmd/trillian_log_server@v1.5.1 165 | ``` 166 | 167 | ```bash 168 | sudo cp ~/go/bin/trillian_log_server /usr/local/bin/ 169 | ``` 170 | 171 | ```bash 172 | go install github.com/google/trillian/cmd/trillian_log_signer@v1.5.1 173 | ``` 174 | 175 | ```bash 176 | sudo cp ~/go/bin/trillian_log_signer /usr/local/bin/ 177 | ``` 178 | 179 | ```bash 180 | go install github.com/google/trillian/cmd/createtree@v1.5.1 181 | ``` 182 | 183 | ```bash 184 | sudo cp ~/go/bin/createtree /usr/local/bin/ 185 | ``` 186 | 187 | ### Run trillian 188 | 189 | The following is best run in two terminals which are then left open (this helps for debugging) 190 | 191 | ```bash 192 | trillian_log_server -http_endpoint=localhost:8090 -rpc_endpoint=localhost:8091 --logtostderr ... 193 | ``` 194 | 195 | ```bash 196 | trillian_log_signer --logtostderr --force_master --http_endpoint=localhost:8190 -rpc_endpoint=localhost:8191 --batch_size=1000 --sequencer_guard_window=0 --sequencer_interval=200ms 197 | ``` 198 | 199 | Alternatively, create bare minimal systemd services 200 | 201 | ```bash 202 | sudo bash -c 'cat << EOF > /etc/systemd/system/trillian_log_server.service 203 | [Unit] 204 | Description=trillian_log_server 205 | After=network-online.target 206 | Wants=network-online.target 207 | StartLimitIntervalSec=600 208 | StartLimitBurst=5 209 | 210 | [Service] 211 | ExecStart=/usr/local/bin/trillian_log_server -http_endpoint=localhost:8090 -rpc_endpoint=localhost:8091 --logtostderr ... 212 | Restart=on-failure 213 | RestartSec=5s 214 | 215 | [Install] 216 | WantedBy=multi-user.target 217 | EOF' 218 | ``` 219 | 220 | ```bash 221 | sudo bash -c 'cat << EOF > /etc/systemd/system/trillian_log_signer.service 222 | [Unit] 223 | Description=trillian_log_signer 224 | After=network-online.target 225 | Wants=network-online.target 226 | StartLimitIntervalSec=600 227 | StartLimitBurst=5 228 | 229 | [Service] 230 | ExecStart=/usr/local/bin/trillian_log_signer --logtostderr --force_master --http_endpoint=localhost:8190 -rpc_endpoint=localhost:8191 --batch_size=1000 --sequencer_guard_window=0 --sequencer_interval=200ms 231 | Restart=on-failure 232 | RestartSec=5s 233 | 234 | [Install] 235 | WantedBy=multi-user.target 236 | EOF' 237 | ``` 238 | 239 | Enable systemd services 240 | 241 | ```bash 242 | sudo systemctl daemon-reload 243 | sudo systemctl enable trillian_log_server.service 244 | sudo systemctl start trillian_log_server.service 245 | sudo systemctl status trillian_log_server.service 246 | sudo systemctl enable trillian_log_signer.service 247 | sudo systemctl start trillian_log_signer.service 248 | sudo systemctl status trillian_log_signer.service 249 | ``` 250 | 251 | ```bash 252 | Created symlink /etc/systemd/system/multi-user.target.wants/trillian_log_server.service → /etc/systemd/system/trillian_log_server.service. 253 | ● trillian_log_server.service - trillian_log_server 254 | Loaded: loaded (/etc/systemd/system/trillian_log_server.service; enabled; vendor preset: enabled) 255 | Active: active (running) since Thu 2021-09-30 17:41:49 UTC; 8s ago 256 | Created symlink /etc/systemd/system/multi-user.target.wants/trillian_log_signer.service → /etc/systemd/system/trillian_log_signer.service. 257 | ● trillian_log_signer.service - trillian_log_signer 258 | Loaded: loaded (/etc/systemd/system/trillian_log_signer.service; enabled; vendor preset: enabled) 259 | Active: active (running) since Thu 2021-09-30 17:42:05 UTC; 12s ago 260 | ``` 261 | 262 | ### Install CTFE server 263 | 264 | ```bash 265 | go install github.com/google/certificate-transparency-go/trillian/ctfe/ct_server@latest 266 | ``` 267 | 268 | ```bash 269 | sudo cp ~/go/bin/ct_server /usr/local/bin/ 270 | ``` 271 | 272 | ### Create a private key 273 | 274 | > **Warning** 275 | > The following section dumps out keys into the home directory. This is only recommended if you do not greatly care about the security of this machine 276 | > If you do care, place them into a more secure location and chmod to a secure level of file permissions. 277 | 278 | Create a key pair with the following command: 279 | 280 | ```bash 281 | openssl ecparam -genkey -name prime256v1 -noout -out unenc.key 282 | openssl ec -in unenc.key -out privkey.pem -des3 283 | ``` 284 | 285 | Extract the public key from the key-pair: 286 | 287 | ```bash 288 | openssl ec -in privkey.pem -pubout -out ctfe_public.pem 289 | ``` 290 | 291 | Feel free to remove the unencrypted key: 292 | 293 | ```bash 294 | rm unenc.key 295 | ``` 296 | 297 | > **Note** 298 | > The private key needs a passphrase, remember it as you will need it for `your_passphrase` when we create the `ct.cfg` further down. 299 | 300 | > **Note** 301 | > You will need the ctfe_public.pem file for the TUF root of cosign, with the sign-container section towards the end 302 | 303 | ### Create a Tree ID 304 | 305 | > **Note** 306 | > `trillian_log_server` needs to be running for this command to execute 307 | 308 | ```bash 309 | LOG_ID="$(createtree --admin_server localhost:8091)" 310 | ``` 311 | 312 | ### Set up the config file 313 | 314 | ```bash 315 | cat > ct.cfg <` to the one you used 331 | when generating the private key. 332 | 333 | > **Note** 334 | > `fulcio-root.pem` is the root ID certificate, we created in [06-fulcio](06-fulcio.md). 335 | 336 | ```bash 337 | sudo mkdir -p /etc/ctfe-config/ 338 | sudo cp ct.cfg /etc/ctfe-config/ 339 | sudo cp fulcio-root.pem /etc/ctfe-config/ 340 | sudo cp privkey.pem /etc/ctfe-config/ 341 | ``` 342 | 343 | ### Start the CT log 344 | 345 | ```bash 346 | ct_server -logtostderr -log_config /etc/ctfe-config/ct.cfg -log_rpc_server localhost:8091 -http_endpoint 0.0.0.0:6105 347 | ``` 348 | 349 | > 📝 The `-http_endpoint` flag uses the internal private IP. We don't need this facing externally 350 | (for this tutorial at least) 351 | 352 | You may create a bare minimal systemd service 353 | 354 | ```bash 355 | sudo bash -c 'cat << EOF > /etc/systemd/system/ct_server.service 356 | [Unit] 357 | Description=ct_server 358 | After=network-online.target 359 | Wants=network-online.target 360 | StartLimitIntervalSec=600 361 | StartLimitBurst=5 362 | 363 | [Service] 364 | ExecStart=/usr/local/bin/ct_server -logtostderr -log_config /etc/ctfe-config/ct.cfg -log_rpc_server localhost:8091 -http_endpoint 0.0.0.0:6105 365 | Restart=on-failure 366 | RestartSec=5s 367 | 368 | [Install] 369 | WantedBy=multi-user.target 370 | EOF' 371 | ``` 372 | 373 | ```bash 374 | sudo systemctl daemon-reload 375 | sudo systemctl enable ct_server.service 376 | sudo systemctl start ct_server.service 377 | sudo systemctl status ct_server.service 378 | ``` 379 | -------------------------------------------------------------------------------- /src/08-configure-registry.md: -------------------------------------------------------------------------------- 1 | # Configure Container Registry 2 | 3 | To switch things up, we will use Github Container registry (ghcr.io) 4 | to push an image and a signature with cosign. You can however 5 | using an OCI registry, [see here](https://github.com/sigstore/cosign#registry-support) 6 | for a list of those currently supported by cosign. 7 | 8 | First, let's create an image. You can use the following `Dockerfile` or any existing image 9 | you already have locally: 10 | 11 | ```bash 12 | cat > Dockerfile < --password-stdin 31 | ``` 32 | 33 | ## Tag and push an image 34 | 35 | Now we can tag and push our image: 36 | 37 | ```bash 38 | docker tag SOURCE_IMAGE_NAME:VERSION ghcr.io/TARGET_OWNER/TARGET_IMAGE_NAME:VERSION 39 | ``` 40 | 41 | Push re-tagged imaged to the container registry: 42 | 43 | ```bash 44 | docker push ghcr.io/OWNER/IMAGE_NAME:VERSION 45 | ``` 46 | 47 | Example: 48 | 49 | ```bash 50 | docker tag sigstore-thw:latest ghcr.io/lukehinds/sigstore-thw:latest 51 | docker push ghcr.io/lukehinds/sigstore-thw:latest 52 | The push refers to repository [ghcr.io/lukehinds/sigstore-thw] 53 | cb381a32b229: Pushed 54 | latest: digest: sha256:568999d4aedd444465c442617666359ddcd4dc117b22375983d2576c3847c9ba size: 528 55 | ``` 56 | -------------------------------------------------------------------------------- /src/09-cosign.md: -------------------------------------------------------------------------------- 1 | # Cosign 2 | 3 | We will now install cosign. It is assumed from now, that cosign will 4 | be run on a machine local to you (such as your laptop or PC), and outside of the sigstore infrastructure. 5 | 6 | ## Install cosign 7 | 8 | Head the [releases page for cosign v1.0](https://github.com/sigstore/cosign/releases/tag/v1.11.1) 9 | and download a release specific to your hardware (MacOS, Linux, Windows) 10 | 11 | Also download the cosign public key, signature for your architecture. 12 | 13 | * `release-cosign.pub` 14 | * `cosign-$OS-$ARCH.sig` 15 | 16 | Verify the signing. 17 | 18 | ### Linux binary 19 | 20 | Download required files: 21 | 22 | ```bash 23 | curl -fsSL --remote-name-all https://github.com/sigstore/cosign/releases/download/v1.11.1/{cosign-linux-amd64,release-cosign.pub,cosign-linux-amd64.sig} 24 | ``` 25 | 26 | Verify signature: 27 | 28 | ```bash 29 | openssl dgst -sha256 -verify release-cosign.pub -signature <(cat cosign-linux-amd64.sig | base64 -d) cosign-linux-amd64 30 | Verified OK 31 | ``` 32 | 33 | Remove signature files: 34 | 35 | ```bash 36 | rm cosign-linux-amd64.sig release-cosign.pub 37 | ``` 38 | 39 | Install cosign: 40 | 41 | ```bash 42 | chmod +x cosign-linux-amd64 43 | sudo cp cosign-linux-amd64 /usr/local/bin/cosign 44 | ``` 45 | 46 | ### MacOS binary 47 | 48 | Download required files: 49 | 50 | ```bash 51 | curl -fsSL --remote-name-all https://github.com/sigstore/cosign/releases/download/v1.11.1/{cosign-darwin-amd64,release-cosign.pub,cosign-darwin-amd64.sig} 52 | ``` 53 | 54 | Verify signature: 55 | 56 | ```bash 57 | openssl dgst -sha256 -verify release-cosign.pub -signature <(cat cosign-darwin-amd64.sig | base64 -D) cosign-darwin-amd64 58 | Verified OK 59 | ``` 60 | 61 | Remove signature files: 62 | 63 | ```bash 64 | rm cosign-darwin-amd64.sig release-cosign.pub 65 | ``` 66 | 67 | Install cosign: 68 | 69 | ```bash 70 | chmod +x cosign-darwin-amd64 71 | sudo cp cosign-darwin-amd64 /usr/local/bin/cosign 72 | ``` 73 | -------------------------------------------------------------------------------- /src/10-sign-container.md: -------------------------------------------------------------------------------- 1 | # Sign Container 2 | 3 | We are now ready to sign our container using our own sigstore infrastructure 4 | 5 | But before we do that, we need to use our own TUF public key file, you might remember created this when deploying the certificate transparency server. 6 | 7 | Have this file locally and set it as an environment variable: 8 | 9 | ```bash 10 | export SIGSTORE_CT_LOG_PUBLIC_KEY_FILE="/path/to/ctfe_public.pem" 11 | ``` 12 | 13 | ```bash 14 | COSIGN_EXPERIMENTAL=1 cosign sign --oidc-issuer "https://oauth2.example.com/auth" --fulcio-url "https://fulcio.example.com" --rekor-url "https://rekor.example.com" ghcr.io//sigstore-thw:latest 15 | ``` 16 | 17 | > :notebook: `COSIGN_EXPERIMENTAL` does as it says, you're trying out an experimental feature here. 18 | 19 | > 📝 If you receive an `UNAUTHORIZED: authentication required` error. You need 20 | to reauthenticate with your PAT in GitHub Container Registry again, refer to [Configure registry](08-configure-registry.md) 21 | 22 | An example run: 23 | 24 | ```bash 25 | COSIGN_EXPERIMENTAL=1 cosign sign -oidc-issuer https://oauth2.decodebytes.sh/auth -fulcio-url https://fulcio.decodebytes.sh --rekor-url https://rekor.decodebytes.sh ghcr.io/lukehinds/sigstore-thw:latest 26 | Generating ephemeral keys... 27 | Retrieving signed certificate... 28 | Your browser will now be opened to: 29 | https://oauth2.decodebytes.sh/auth/auth?access_type=online&client_id=sigstore&code_challenge=ZP91ElDffEaUAJxCTYpr_RfpvLHTx8a9WEuiDJiMQT0&code_challenge_method=S256&nonce=1vzuVUvfZ4caqLwqJlUsm0lJglb&redirect_uri=http%3A%2F%2Flocalhost%3A5556%2Fauth%2Fcallback&response_type=code&scope=openid+email&state=1vzuVUvXnKzS2hJnLzxkiDt0qOw 30 | warning: uploading to the transparency log at https://rekor.decodebytes.sh for a private image, please confirm [Y/N]: Y 31 | tlog entry created with index: 11 32 | Pushing signature to: ghcr.io/lukehinds/sigstore-thw:latest:sha256-568999d4aedd444465c442617666359ddcd4dc117b22375983d2576c3847c9ba.sig 33 | ``` 34 | 35 | ## Verifying the signing 36 | 37 | We will now verify the signing, but before we do we need to tell cosign about our fulcio root. 38 | 39 | Grab your `fulcio-root.pem` cerficate you generated on the fulcio server (and also copied to the certificate transparency server) 40 | 41 | Set the following environment variable: 42 | 43 | ```bash 44 | export SIGSTORE_ROOT_FILE="$HOME/fulcio-root.pem" 45 | ``` 46 | 47 | Download the Rekor public key: 48 | 49 | ```bash 50 | wget -O publicKey.pem https://rekor.example.com/api/v1/log/publicKey 51 | ``` 52 | 53 | Set it in the appropriate environment variable: 54 | 55 | ```bash 56 | export SIGSTORE_REKOR_PUBLIC_KEY="$PWD/publicKey.pem" 57 | ``` 58 | 59 | We can now verify: 60 | 61 | ```bash 62 | COSIGN_EXPERIMENTAL=1 cosign verify --certificate-identity --certificate-oidc-issuer https:///auth --rekor-url https://rekor.example.com ghcr.io//sigstore-thw:latest 63 | ``` 64 | 65 | Replace `` with the e-mail address of the identity you used to sign to your Dex instance. 66 | An example: 67 | 68 | ```bash 69 | COSIGN_EXPERIMENTAL=1 cosign verify --certificate-identity lhinds@redhat.com --certificate-oidc-issuer https://oauth2.decodebytes.sh/auth --rekor-url https://rekor.decodebytes.sh ghcr.io/lukehinds/sigstore-thw 70 | 71 | Verification for ghcr.io/lukehinds/sigstore-thw:latest -- 72 | The following checks were performed on each of these signatures: 73 | - The cosign claims were validated 74 | - The claims were present in the transparency log 75 | - The signatures were integrated into the transparency log when the certificate was valid 76 | - Any certificates were verified against the Fulcio roots. 77 | Certificate subject: [lhinds@redhat.com] 78 | {"critical":{"identity":{"docker-reference":"ghcr.io/lukehinds/sigstore-thw"},"image":{"docker-manifest-digest":"sha256:568999d4aedd444465c442617666359ddcd4dc117b22375983d2576c3847c9ba"},"type":"cosign container image signature"},"optional":null} 79 | ``` 80 | 81 | ## Congrats 82 | 83 | If you got this far well done for completing the tutorial! 84 | 85 | ![glass](images/glass.gif) 86 | 87 | ## What Next 88 | 89 | If you're not already part of the sigstore community, come and join us on our slack channel; [Invite link](https://join.slack.com/t/sigstore/shared_invite/zt-mhs55zh0-XmY3bcfWn4XEyMqUUutbUQ) 90 | and tell us abour your ideas! 91 | 92 | If you want to improve this guide, please make an issue or better still a pull request! 93 | 94 | Don't forget to delete your instances and not take on unwanted costs! 95 | 96 | ## Having issues, not working? 97 | 98 | Raise an issue (best option, as others can learn) or message me on the [sigstore slack](https://join.slack.com/t/sigstore/shared_invite/zt-mhs55zh0-XmY3bcfWn4XEyMqUUutbUQ), I'm always happy to help. 99 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Sigstore the Hard Way 2 | 3 | Welcome to sigstore the hard way. 4 | 5 | The driver for this project is to get potential users, developers or collaborators familiar with the inner workings of 6 | sigstore's infrastructure. 7 | 8 | To best achieve a good familiarity with sigstore, we will walk through the whole process manually. 9 | 10 | Building "by hand" provides a view of how each component project in sigstore glues together, while deliberately avoiding automation. This 11 | means no Dockerfiles or deployment framework playbooks. Everything is set up manually. 12 | 13 | With 'sigstore the hard way' we will install, configure and run the following components to provide a 'keyless' signing 14 | infrastructure. 15 | 16 | 1. [Fulcio](https://github.com/sigstore/fulcio) WebPKI 17 | 2. [Rekor](https://github.com/sigstore/rekor), signature transparency log and timestamping authority 18 | 3. [Certificate Transparency Log](https://github.com/google/certificate-transparency-go/tree/master/trillian) 19 | 4. [Dex](https://github.com/dexidp/dex), OpenID Connect provider 20 | 5. [Cosign](https://github.com/sigstore/cosign), container (and more) signing and verifying tool 21 | 22 | ## Requirements 23 | 24 | This tutorial leverages the [GCP](https://cloud.google.com/) for the provisioning of the compute 25 | infrastructure required to bootstrap the sigstore infra from the ground up. 26 | Free credits are available on [Sign up](https://cloud.google.com/free/). For when it comes to saving costs, the recommendation 27 | is to shutdown any instances when you're not using them and once you have completed the tutorial, delete 28 | all the instances, networks etc. 29 | 30 | You can of course use local machines if you have them, or any other provider such as AWS, Azure (pull requests welcomed!) 31 | 32 | The only other requirement is a domain name, where you have the ability to create some subdomains. We need a domain 33 | for an OpenID Connect session (providers don't always like redirect_urls to IP addresses). It's up to you who you use, any provider will do. If you already have a domain, it makes sense to use that. We won't be messing with the root domain if you're already running something there, just creating subdomains (e.g. rekor.example.com, fulcio.example.com) 34 | 35 | ## Certificate Authority 36 | 37 | For the Certificate Authority we will have three options to choose from: 38 | 39 | * File CA 40 | * [SoftHSM](http://www.softhsm.org/) 41 | * Google's Certificate Transparency Service 42 | 43 | The above are listed in order of setup ease. If you just want to kick the tyres and don't need a secure CA, you can use the File CA. 44 | 45 | Google's is a paid service, but easy to set up. SoftHSM is completely free, but requires a little more setup (but nothing 46 | too challenging) 47 | 48 | Last of all we will sign a container image using cosign. 49 | 50 | ### Copyright 51 | 52 | If you have not guessed by name, this is based off, and comes with credit to [Kelsey Hightower's Kubernetes the Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way) 53 | 54 |
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. 55 | 56 | ## Having issues, something not working? 57 | 58 | [Raise an issue](https://github.com/lukehinds/sigstore-the-hard-way/issues/new/choose) (best option, as others can learn) or message me on the [sigstore slack](https://join.slack.com/t/sigstore/shared_invite/zt-mhs55zh0-XmY3bcfWn4XEyMqUUutbUQ), I'm always happy to help. 59 | -------------------------------------------------------------------------------- /src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [Introduction](README.md) 4 | 5 | - [Prerequisites](./01-prerequisites.md) 6 | - [Compute Resources](./02-compute-resources.md) 7 | - [Domain Configuration](./03-domain-configuration.md) 8 | - [rekor](./04-rekor.md) 9 | - [Dex (oauth2)](./05-dex.md) 10 | - [Fulcio](./06-fulcio.md) 11 | - [Certificate Transparency](./07-certifcate-transparency.md) 12 | - [Configure OCI Registry](./08-configure-registry.md) 13 | - [Setup Cosign](./09-cosign.md) 14 | - [Sign a Container](./10-sign-container.md) 15 | 16 | ----------- 17 | 18 | [Contributors](misc/contributors.md) 19 | -------------------------------------------------------------------------------- /src/contributors.md: -------------------------------------------------------------------------------- 1 | # Thanks 2 | -------------------------------------------------------------------------------- /src/images/app-reg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/app-reg.png -------------------------------------------------------------------------------- /src/images/ca_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/ca_type.png -------------------------------------------------------------------------------- /src/images/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/create.png -------------------------------------------------------------------------------- /src/images/ecp384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/ecp384.png -------------------------------------------------------------------------------- /src/images/enable_gcp_ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/enable_gcp_ca.png -------------------------------------------------------------------------------- /src/images/glass.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/glass.gif -------------------------------------------------------------------------------- /src/images/label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/label.png -------------------------------------------------------------------------------- /src/images/oauth-consent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/oauth-consent.png -------------------------------------------------------------------------------- /src/images/oauth-credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/oauth-credentials.png -------------------------------------------------------------------------------- /src/images/oauth-creds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/oauth-creds.png -------------------------------------------------------------------------------- /src/images/oauth-redirect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/oauth-redirect.png -------------------------------------------------------------------------------- /src/images/rev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/rev.png -------------------------------------------------------------------------------- /src/images/scopes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/scopes.png -------------------------------------------------------------------------------- /src/images/subj_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/subj_name.png -------------------------------------------------------------------------------- /src/images/user-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/user-email.png -------------------------------------------------------------------------------- /src/images/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/view.png -------------------------------------------------------------------------------- /src/images/view_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stacklok/sigstore-the-hard-way/9f37d7c94e4ba072512e5948c1f6134414d97a73/src/images/view_two.png -------------------------------------------------------------------------------- /src/misc/contributors.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | Here is a list of the contributors who have helped improving sigstore the hardway. Big 4 | shout-out to them! 5 | 6 | - Nathan Smith ([nsmith5](https://github.com/nsmith5)) 7 | - Viacheslav Vasilyev ([avoidik](https://github.com/avoidik)) 8 | - Ayush Ambastha ([AyushAmbastha](https://github.com/AyushAmbastha)) 9 | - Axel Simon ([axelsimon](https://github.com/axelsimon)) 10 | - Steve Morgan ([rebelopsio](https://github.com/rebelopsio)) 11 | - [mc-slava](https://github.com/mc-slava) 12 | - [Juan Antonio Osorio](https://github.com/JAORMX) 13 | 14 | If you feel you're missing from this list, feel free to add yourself in a PR. 15 | --------------------------------------------------------------------------------