Skip to content

Commit bcdbf95

Browse files
committed
docs: updates
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
1 parent 93fb9bb commit bcdbf95

File tree

2 files changed

+184
-37
lines changed

2 files changed

+184
-37
lines changed

.github/ruleset.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"id": 8566281,
3+
"name": "default",
4+
"target": "branch",
5+
"source_type": "Repository",
6+
"source": "goreleaser/example-secure",
7+
"enforcement": "active",
8+
"conditions": {
9+
"ref_name": {
10+
"exclude": [],
11+
"include": [
12+
"~DEFAULT_BRANCH"
13+
]
14+
}
15+
},
16+
"rules": [
17+
{
18+
"type": "deletion"
19+
},
20+
{
21+
"type": "non_fast_forward"
22+
},
23+
{
24+
"type": "copilot_code_review",
25+
"parameters": {
26+
"review_on_push": true,
27+
"review_draft_pull_requests": true
28+
}
29+
},
30+
{
31+
"type": "required_signatures"
32+
},
33+
{
34+
"type": "required_linear_history"
35+
}
36+
],
37+
"bypass_actors": []
38+
}

README.md

Lines changed: 146 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,120 @@
11
# secure-example
22

3-
This is an example repository showing how to securely release using GoReleaser
4-
and GitHub Actions.
3+
This example outlines how to securely release using GoReleaser and GitHub
4+
Actions.
55

6-
## Workflows
6+
## Components
77

8-
- `build`: runs tests
9-
- `release`: runs goreleaser
10-
- `security`: security scans: grype, govulncheck, codeql, license-check
8+
We'll go over a few things: GitHub settings, GoReleaser configuration, and
9+
GitHub actions.
1110

12-
## How it works
11+
### GitHub Settings
1312

14-
GoReleaser manages the entire thing, basically.
13+
These are some things I recommend you do:
1514

16-
It will:
15+
1. General > Require contributors to sign off on web-based commits Loading
16+
1. General > Enable release immutability
17+
1. Actions > General > Require approval for all external contributors
18+
1. Actions > General > Read repository contents and packages permissions
19+
1. Rules > New Ruleset > Import a ruleset > [this file](./.github/ruleset.json)
20+
1. Advanced Security > Private vulnerability reporting
21+
1. Advanced Security > Dependency graph
22+
1. Advanced Security > Automatic dependency submission
23+
1. Advanced Security > Dependabot security updates
1724

18-
- build using the Go Mod Proxy as source of truth
19-
- create archives
20-
- call `syft` to create the SBOMs
21-
- create the checksum file
22-
- sign it with `cosign`
23-
- create the github release
24-
- push artifacts there
25-
- create a docker image (with SBOM) using the binary it just built (thus, the binary inside the docker image is the same as the one released)
26-
- sign the docker image with `cosign` as well
25+
There's much more you can change, these are the things I usually do.
2726

28-
## Verifying
27+
### GoReleaser Configuration
28+
29+
The [provided configuration](./.goreleaser.yaml) is commented out and each section
30+
links to the relevant documentation, but here's a rundown:
31+
32+
- we build for a couple of platforms using the Go mod proxy
33+
- we create archives for both the binaries as well as for the source
34+
- we create and sign a checksums file (using [Cosign][cosign])
35+
- we create SBOMs of all archives (using [Syft][syft])
36+
- all these files are uploaded to the GitHub release
37+
- we create a Docker image manifest, which also includes SBOMs
38+
- we then sign the image
39+
40+
### GitHub Actions
41+
42+
We have 3 workflows set up, let's go over them.
43+
44+
#### Build
45+
46+
The [build workflow](./.github/workflows/build.yml) doesn't do much: it checks
47+
out the code, installs Go, and runs `go test`.
48+
49+
#### Security
50+
51+
The [security workflow](./.github/workflows/security.yml) does a lot more, as it
52+
has a couple of jobs:
53+
54+
1. `codeql`: as the name implies, runs the recommended [CodeQL][codeql] queries for Go and
55+
Actions;
56+
1. `grype`: runs [Grype][], which scans for known vulnerabilities;
57+
1. `govulncheck`: runs the standard [Go vulnerability checker][govulncheck];
58+
1. `dependency-review`: runs only on pull requests, and checks if any
59+
dependencies being added or updated are allowed.
60+
61+
All these jobs report their status using
62+
[Static Analysis Results Interchange Format (SARIF)](https://sarifweb.azurewebsites.net/),
63+
so any findings will show as security alerts in the
64+
[Security > Code scanning](/security/code-scanning) tab.
65+
66+
#### Release
67+
68+
Finally, the [release workflow](./.github/workflows/release.yml).
69+
Its main job is to, well, release our software, and it uses [GoReleaser][] for
70+
that (surprise!).
71+
But to do that, we first set up [Docker][docker], [Cosign][cosign], and
72+
[Syft][syft].
73+
Then, we run the glorious [goreleaser-action][], which does all the heavy
74+
lifting.
75+
Then, after all is said and done, we attest our build artifacts.
76+
77+
#### Why all the SHA1s?
78+
79+
As you may have noticed, all the actions are pinned to the SHA1 of their
80+
respective tags.
81+
82+
This is recommended, as an attacker might take over an action and re-publish
83+
malicious code under the same tags.
84+
85+
Using only the major versions (like `@v4`) is also not so good, as you are then
86+
even more clueless about what is actually being run.
87+
88+
If you want to pin all the actions in your repositories, I recommend using
89+
[pinata][].
90+
91+
## Releasing
92+
93+
To create a new release, create and push a new tag.
94+
You can get the next semantic version using [svu][]:
95+
96+
```bash
97+
git tag -s $(svu n)
98+
git push --tags
99+
```
100+
101+
And then go over to [the actions tab](/actions/workflows/release.yml) and wait
102+
for the release to finish.
103+
104+
## Verifying the artifacts
105+
106+
Your users will need to know how to verify the artifacts, and this is what this
107+
section is all about.
108+
109+
The first thing we need to do, is get the current latest version:
29110

30111
```bash
31112
export VERSION="$(gh release list -L 1 -R goreleaser/example-secure --json=tagName -q '.[] | .tagName')"
32113
```
33114

34-
### Checksums
115+
Then, we download the `checksums.txt` file, and verify its signature:
35116

36-
```shell
117+
```bash
37118
wget https://github.com/goreleaser/example-secure/releases/download/$VERSION/checksums.txt
38119
cosign verify-blob \
39120
--certificate-identity 'https://github.com/goreleaser/example-secure/.github/workflows/release.yml@refs/tags/$VERSION' \
@@ -43,53 +124,81 @@ cosign verify-blob \
43124
./checksums.txt
44125
```
45126

127+
This should succeed - which means that we can from now on verify any artifact
128+
from the release with this checksum file!
129+
46130
You can then download any file you want from the release, and verify it with, for example:
47131

48-
```shell
132+
```bash
49133
wget https://github.com/goreleaser/example-secure/releases/download/$VERSION/example_linux_amd64.tar.gz
50134
sha256sum --ignore-missing -c checksums.txt
51135
```
52136

53-
And both should say "OK".
137+
Which should, ideally, say "OK".
54138

55-
### SBOMs
56-
57-
You can then inspect the `.sbom` file to see the entire dependency tree of the
139+
You can then inspect the SBOM file to see the entire dependency tree of the
58140
binary, check for vulnerable dependencies and whatnot.
59141

60142
To get the SBOM of an artifact, you can use the same download URL, adding
61-
`.sbom.json` to the end of the URL:
143+
`.sbom.json` to the end of the URL, and we can then check it out with `grype`:
62144

63-
```shell
145+
```bash
64146
wget https://github.com/goreleaser/example-secure/releases/download/$VERSION/example_linux_amd64.tar.gz.sbom.json
65147
sha256sum --ignore-missing -c checksums.txt
66148
grype sbom:example_linux_amd64.tar.gz.sbom.json
67149
```
68150

69-
### Attestations
70-
71-
This example also publishes build attestations.
72-
You can verify any artifact with:
151+
Finally, we can also use the `gh` CLI to verify the attestations:
73152

74-
```shell
153+
```bash
75154
gh attestation verify \
76155
--owner goreleaser \
77156
*.tar.gz
78157
```
79158

80-
### Docker image
159+
Docker images are a bit simpler, you can verify them with [Cosign][cosign]
160+
and [Grype][grype] directly, and check the attestations as well.
161+
162+
Signature:
81163

82-
```shell
164+
```bash
83165
cosign verify \
84166
--certificate-identity 'https://github.com/goreleaser/example-secure/.github/workflows/release.yml@refs/tags/$VERSION' \
85167
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
86168
ghcr.io/goreleaser/example-secure:$VERSION
87169
```
88170

89-
The images are also attested:
171+
Vulnerabilities:
172+
173+
```bash
174+
grype docker:ghcr.io/goreleaser/example-secure:$VERSION
175+
```
176+
177+
Attestations:
90178

91-
```shell
179+
```bash
92180
gh attestation verify \
93181
--owner goreleaser \
94182
oci://ghcr.io/goreleaser/example-secure:$VERSION
95183
```
184+
185+
If all these checks are OK, you have a pretty good indication that everything
186+
is good.
187+
188+
---
189+
190+
I really hope this helps - and please feel free to open PRs improving things you
191+
think need improving, or issues to discuss any concerns you might have.
192+
193+
Thanks for reading!
194+
195+
[syft]: https://github.com/anchore/syft
196+
[cosign]: https://github.com/sigstore/cosign
197+
[grype]: https://github.com/anchore/grype
198+
[codeql]: https://codeql.github.com/
199+
[govulncheck]: https://go.dev/blog/govulncheck
200+
[goreleaser]: https://goreleaser.com
201+
[docker]: https://docker.io
202+
[pinata]: https://github.com/caarlos0/pinata
203+
[svu]: https://github.com/caarlos0/svu
204+
[goreleaser-action]: https://github.com/goreleaser/goreleaser-action

0 commit comments

Comments
 (0)