Add example of push and sign OCI artifacts

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
pull/3540/head
Stefan Prodan 2 years ago
parent 56807fddf6
commit 6681cd05a9
No known key found for this signature in database
GPG Key ID: 3299AEB0E4085BAF

@ -134,18 +134,25 @@ jobs:
flux tag artifact $OCI_REPO:$(git rev-parse --short HEAD) --tag staging flux tag artifact $OCI_REPO:$(git rev-parse --short HEAD) --tag staging
``` ```
Example workflow for publishing Kubernetes manifests bundled as OCI artifacts to Docker Hub: ### Push and sign Kubernetes manifests to container registries
Example workflow for publishing Kubernetes manifests bundled as OCI artifacts
which are signed with Cosign and GitHub OIDC:
```yaml ```yaml
name: push-artifact-production name: push-sign-artifact
on: on:
push: push:
tags: branches:
- '*' - 'main'
permissions:
packages: write # needed for ghcr.io access
id-token: write # needed for keyless signing
env: env:
OCI_REPO: "oci://docker.io/my-org/app-config" OCI_REPO: "oci://ghcr.io/my-org/manifests/${{ github.event.repository.name }}"
jobs: jobs:
kubernetes: kubernetes:
@ -155,23 +162,24 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup Flux CLI - name: Setup Flux CLI
uses: fluxcd/flux2/action@main uses: fluxcd/flux2/action@main
- name: Login to Docker Hub - name: Setup Cosign
uses: sigstore/cosign-installer@main
- name: Login to GHCR
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKER_USERNAME }} registry: ghcr.io
password: ${{ secrets.DOCKER_PASSWORD }} username: ${{ github.actor }}
- name: Generate manifests password: ${{ secrets.GITHUB_TOKEN }}
run: | - name: Push and sign manifests
kustomize build ./manifests/production > ./deploy/app.yaml
- name: Push manifests
run: |
flux push artifact $OCI_REPO:$(git tag --points-at HEAD) \
--path="./deploy" \
--source="$(git config --get remote.origin.url)" \
--revision="$(git tag --points-at HEAD)/$(git rev-parse HEAD)"
- name: Deploy manifests to production
run: | run: |
flux tag artifact $OCI_REPO:$(git tag --points-at HEAD) --tag production digest_url=$(flux push artifact \
$OCI_REPO:$(git rev-parse --short HEAD) \
--path="./manifests" \
--source="$(git config --get remote.origin.url)" \
--revision="$(git branch --show-current)/$(git rev-parse HEAD)" |\
jq -r '. | .repository + "@" + .digest')
cosign sign $digest_url
``` ```
### End-to-end testing ### End-to-end testing

@ -43,13 +43,14 @@ The command can read the credentials from '~/.docker/config.json' but they can a
--source="$(git config --get remote.origin.url)" \ --source="$(git config --get remote.origin.url)" \
--revision="$(git branch --show-current)/$(git rev-parse HEAD)" --revision="$(git branch --show-current)/$(git rev-parse HEAD)"
# Push and sign artifact with cosgin # Push and sign artifact with cosign
digest_url = $(flux push artifact \ digest_url = $(flux push artifact \
oci://ghcr.io/org/config/app:$(git rev-parse --short HEAD) \ oci://ghcr.io/org/config/app:$(git rev-parse --short HEAD) \
--source="$(git config --get remote.origin.url)" \ --source="$(git config --get remote.origin.url)" \
--revision="$(git branch --show-current)/$(git rev-parse HEAD)" \ --revision="$(git branch --show-current)/$(git rev-parse HEAD)" \
--path="./path/to/local/manifest.yaml" | \ --path="./path/to/local/manifest.yaml" \
jq -r '. | .image + "@" + .digest') --output json | \
jq -r '. | .repository + "@" + .digest')
cosign sign $digest_url cosign sign $digest_url
# Push manifests passed into stdin to GHCR # Push manifests passed into stdin to GHCR
@ -116,7 +117,7 @@ func init() {
pushArtifactCmd.Flags().Var(&pushArtifactArgs.provider, "provider", pushArtifactArgs.provider.Description()) pushArtifactCmd.Flags().Var(&pushArtifactArgs.provider, "provider", pushArtifactArgs.provider.Description())
pushArtifactCmd.Flags().StringSliceVar(&pushArtifactArgs.ignorePaths, "ignore-paths", excludeOCI, "set paths to ignore in .gitignore format") pushArtifactCmd.Flags().StringSliceVar(&pushArtifactArgs.ignorePaths, "ignore-paths", excludeOCI, "set paths to ignore in .gitignore format")
pushArtifactCmd.Flags().StringVarP(&pushArtifactArgs.output, "output", "o", "", pushArtifactCmd.Flags().StringVarP(&pushArtifactArgs.output, "output", "o", "",
"the format in which the artifact digest should be printed. can be 'json' or 'yaml'") "the format in which the artifact digest should be printed, can be 'json' or 'yaml'")
pushCmd.AddCommand(pushArtifactCmd) pushCmd.AddCommand(pushArtifactCmd)
} }
@ -207,15 +208,15 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
} }
info := struct { info := struct {
URL string `json:"url"` URL string `json:"url"`
Image string `json:"image"` Repository string `json:"repository"`
Tag string `json:"tag"` Tag string `json:"tag"`
Digest string `json:"digest"` Digest string `json:"digest"`
}{ }{
URL: fmt.Sprintf("oci://%s", digestURL), URL: fmt.Sprintf("oci://%s", digestURL),
Image: fmt.Sprintf("%s/%s", digest.RegistryStr(), digest.RepositoryStr()), Repository: digest.Repository.Name(),
Tag: tag.TagStr(), Tag: tag.TagStr(),
Digest: digest.DigestStr(), Digest: digest.DigestStr(),
} }
switch pushArtifactArgs.output { switch pushArtifactArgs.output {

Loading…
Cancel
Save