Skip to content

Commit

Permalink
fix: added image signing DOC-962
Browse files Browse the repository at this point in the history
  • Loading branch information
karl-cardenas-coding committed Jan 23, 2024
1 parent b59c29e commit a9b33e3
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 75 deletions.
141 changes: 86 additions & 55 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Release to Production

on:
push:
branches: [ main ]
branches: [main]

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down Expand Up @@ -45,7 +45,6 @@ jobs:
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/setup-buildx-action@v2


- name: Login to GHCR
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/login-action@v1
Expand All @@ -56,74 +55,106 @@ jobs:

- name: Build and Push Docker Image
if: ${{ steps.version.outputs.VERSION != ''}}
id: build-and-push
uses: docker/build-push-action@v2
with:
context: .
build-args: VERSION=${{steps.version.outputs.VERSION}}
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ github.repository }}:${{steps.version.outputs.VERSION}}


- uses: sigstore/[email protected]

- name: Image Signing
run: |
cosign sign --yes \
-a "repo=${{ github.repository }}" \
-a "workflow=${{ github.workflow }}" \
-a "ref=${{ github.sha }}" \
-a "owner=Spectro Cloud" \
--key env://COSIGN_PRIVATE_KEY --recursive "${TAGS}@${DIGEST}"
env:
TAGS: ghcr.io/${{ github.repository }}:${{steps.dependencies.outputs.VERSION}}
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}

docker-reverse-proxy:
name: "Docker w/Proxy image"
runs-on: ubuntu-latest
outputs:
VERSION: ${{ steps.version.outputs.version }}
steps:
- id: checkout
name: Checkout Repository
uses: actions/checkout@v3

- name: Setup Nodejs
uses: actions/setup-node@v3
with:
node-version: 18

- name: Install dependencies
run: npm ci

- id: version
name: Determine Release Version
run: |
npm install @semantic-release/exec -D
npm install @semantic-release/changelog -D
npm install @semantic-release/git -D
npx semantic-release --dry-run
cat VERSION.env
source VERSION.env
echo "::set-output name=version::$VERSION"
- name: Set up QEMU
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/setup-buildx-action@v2


- name: Login to GHCR
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and Push Docker Image
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile.Caddy
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ github.repository }}:${{steps.version.outputs.VERSION}}-proxy
- id: checkout
name: Checkout Repository
uses: actions/checkout@v3

- name: Setup Nodejs
uses: actions/setup-node@v3
with:
node-version: 18

- name: Install dependencies
run: npm ci

- id: version
name: Determine Release Version
run: |
npm install @semantic-release/exec -D
npm install @semantic-release/changelog -D
npm install @semantic-release/git -D
npx semantic-release --dry-run
cat VERSION.env
source VERSION.env
echo "::set-output name=version::$VERSION"
- name: Set up QEMU
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/setup-buildx-action@v2

- name: Login to GHCR
if: ${{ steps.version.outputs.VERSION != ''}}
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and Push Docker Image
if: ${{ steps.version.outputs.VERSION != ''}}
id: build-and-push
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile.Caddy
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ github.repository }}:${{steps.version.outputs.VERSION}}-proxy

- uses: sigstore/[email protected]

- name: Image Signing
run: |
cosign sign --yes \
-a "repo=${{ github.repository }}" \
-a "workflow=${{ github.workflow }}" \
-a "ref=${{ github.sha }}" \
-a "owner=Spectro Cloud" \
--key env://COSIGN_PRIVATE_KEY --recursive "${TAGS}@${DIGEST}"
env:
TAGS: ghcr.io/${{ github.repository }}:${{steps.dependencies.outputs.VERSION}}
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}

release:
name: "Release"
needs: [docker,docker-reverse-proxy]
needs: [docker, docker-reverse-proxy]
runs-on: ubuntu-latest
steps:
- id: checkout
Expand All @@ -141,4 +172,4 @@ jobs:
- name: "release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
run: npx semantic-release
44 changes: 24 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ Hello Universe is a demo application intended for learning about [Palette](https
<img src="./static/img/demo.gif" alt="drawing" width="400"/>
</p>

# Run App
## Start App

Get started with Hello Universe by choosing between two deployment approaches; docker or a non-docker-based approach.

## Docker
### Docker

Hello Universe is available as a Docker image.
To run Hello Universe issue the following commands:
Expand All @@ -20,7 +20,8 @@ docker pull ghcr.io/spectrocloud/hello-universe:1.1.0
docker run -p 8080:8080 ghcr.io/spectrocloud/hello-universe:1.1.0
```

## Non-Docker
### Non-Docker

To run locally without Docker:

```
Expand All @@ -29,26 +30,23 @@ npm ci
npm run start
```

## Environment Variables
### Environment Variables

Hello Universe accepts the following environment variables:

| Variable | Description | Default |
|-------------|----------------------------------------------------|-----------|
| API_URI | The fully qualified hostname and port of the API server. In a reverse proxy setting this can be the application loadbalancer. | `""` |
| API_VERSION | The API version number. | `1` |
| SVC_URI | The URI to the service API, such as the internal Kubernetes container hostname of the API service. |`""`|
| TOKEN | The API authorization token. This is only used if the API is configured for authorization. |`""`|

| Variable | Description | Default |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------- | ------- |
| API_URI | The fully qualified hostname and port of the API server. In a reverse proxy setting this can be the application loadbalancer. | `""` |
| API_VERSION | The API version number. | `1` |
| SVC_URI | The URI to the service API, such as the internal Kubernetes container hostname of the API service. | `""` |
| TOKEN | The API authorization token. This is only used if the API is configured for authorization. | `""` |

### Connecting to API Server

## Connecting to API Server

Hello Universe's capabilities can be expanded if connected to the [Hello Universe API](https://github.com/spectrocloud/hello-universe-api).
Hello Universe's capabilities can be expanded if connected to the [Hello Universe API](https://github.com/spectrocloud/hello-universe-api).
To connect Hello Universe to the API server, provide the API server's fully qualified hostname and port as an environment variable value.
Be aware that the API server requires an available Postgres database. Checkout [Hello Universe DB](https://github.com/spectrocloud/hello-universe-db) for a dockerized Postgres instance ready for integration with the Hello Universe API.


```shell
API_URI=http://localhost:3000
```
Expand All @@ -61,15 +59,18 @@ docker run -p 8080:8080 -e API_URI=http://localhost:3000 ghcr.io/spectrocloud/he

### Reverse Proxy

A Docker container with a reverse proxy is available. The reverse proxy is usefull for scenarios when you need to deploy the
A Docker container with a reverse proxy is available. The reverse proxy is usefull for scenarios when you need to deploy the
hello universe application into a Kubernetes cluster or similar architectures and need the UI to route requests internal to the hosting platform. An example of such behavior is needing to to reach a private API inside the Kubernetes cluster. **The reverse proxy expects the API to be listening on port `3000`.**

```shell
docker run -p 8080:8080 -p 3000:3000 -e SVC_URI="http://myprivate.api.address.example:3000" -e API_URI="http://myloadbalancer.example:3000" ghcr.io/spectrocloud/hello-universe:1.1.0-proxy
```

# Development
## Image Verification

We sign our images through [Cosign](https://docs.sigstore.dev/signing/quickstart/). Review the [Image Verification](./docs/image-verification.md) page to learn more.

## Development

Create an environment file `.env` file and add the following values:

Expand All @@ -80,39 +81,42 @@ REACT_APP_API_VERSION=1

The `.env` file is how you point to the local development API server. Otherwise, local browser storage is used.


Use the [`docker-compose.yml`](./docker-compose.yml) to start the required services.

```shell
make start-services
```


Next, start the local development server

```shell
make start
```


To stop the docker containers, use the following command.

```shell
make stop-services
```

## Clean

To remove the build folder use the command `make clean`

## Build

To build the hosting assets use the command `make build`

### Development Server

To start the local development server without a proxy use the command `make start`.

### Server w/o Reverse Proxy

To start the Caddy server without a reverse proxy use the command `make start-prod`.

### Server w/o Reverse Proxy

To start the Caddy server with a reverse proxy use the command `make start-proxy`.

## Dependencies
Expand Down
81 changes: 81 additions & 0 deletions docs/image-verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Image Verification

The Tutorials container image is signed using [Sigstore's](https://sigstore.dev/) Cosign. The container image is signed using a cryptographic key pair that is private and stored internally. The public key is available in the official Spectro Cloud documentation repository at [**static/cosign.pub**](https://raw.githubusercontent.com/spectrocloud/librarium/master/static/cosign.pub). Use the public key to verify the authenticity of the container image. You can learn more about the container image signing process by reviewing the [Signing Containers](https://docs.sigstore.dev/signing/signing_with_containers) documentation page.

> [!NOTE]
> Cosign generates a key pair that uses the ECDSA-P256 algorithm for the signature and SHA256 for hashes. The keys are stored in PEM-encoded PKCS8 format.
Use the following command to verify the authenticity of the container image. Replace the image tag with the version you want to verify.

```shell
cosign verify --key https://raw.githubusercontent.com/spectrocloud/librarium/master/static/cosign.pub \
docker pull ghcr.io/spectrocloud/hello-universe:1.1.1
```

If the container image is valid, the following output is displayed. The example output is formatted using `jq` to improve readability.

```shell hideClipboard
Verification for ghcr.io/spectrocloud/hello-universe:1.1.1 --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The signatures were verified against the specified public key
[
{
"critical": {
"identity": {
"docker-reference": "ghcr.io/spectrocloud/hello-universe:1.1.1"
},
"image": {
"docker-manifest-digest": "sha256:285a95a8594883b3748138460182142f5a1b74f80761e2fecb1b86d3c9b9d191"
},
"type": "cosign container image signature"
},
"optional": {
"Bundle": {
"SignedEntryTimestamp": "MEYCIQCZ6FZzNB5wA9+W/lF57jx0qTaszZhg5FxJiBmgIFxPVwIhANnoQQ5gqjr1h93LCq1Td8BohqrxxIvfrXTnT1tYR4i7",
"Payload": {
"body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI0MzU0MzFjNjY1Y2Y2ZGZjYzM0NzI2YWRkNjAzMDVjYjZlMzhlNjVkZmJlMWQ0NWU2ZGVkM2IzNzg3NTYwY2MxIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUM0TFFxYVFDclhOc0VzdkI0ZE84bmtZSWg0L3o5UzdScGVEdUZnUDJwbDJ3SWdOdEJsNElDaHBmT3RnVDBlNW5QTmRMYWt4RTJHcnFFK0tjV1JXSGZPTnpnPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGV1VoeVl6SlhTVVV6WVhCTFRHMWplR3hHUmtoNVZsRkRVVnBYYUFveUsyRnNOVmN2Vmsxc1VISXpkVFJGV2k5V0wwZFBRbTAySzFrNVowWXpWWE16ZEhkMVpWaFpaMlJaWlVadk5XODNRbFZ1TnpCTlVGQjNQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=",
"integratedTime": 1702758491,
"logIndex": 57230483,
"logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"
}
},
"owner": "Spectro Cloud",
"ref": "e597f70be238369ce4f0e5778492a155e23fec17",
"repo": "spectrocloud/hello-universe",
"workflow": "Release"
}
}
]
```

> [!CAUTION]
> Do not use the container image if the authenticity cannot be verified. Verify you downloaded the correct public key and that the container image is from `ghcr.io/spectrocloud/tutorials`.
If the container image is not valid, an error is displayed. The following example shows an error when the container image is not valid.

```shell hideClipboard
cosign verify --key https://raw.githubusercontent.com/spectrocloud/librarium/master/static/cosign.pub \
ghcr.io/spectrocloud/hello-universe:1.1.0
```

```shell hideClipboard
Error: no matching signatures: error verifying bundle: comparing public key PEMs, expected -----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEheVfGYrVn2mIUQ4cxMJ6x09oXf82
zFEMG++p4q8Mf+y2gp7Ae4oUaXk6Q9V7aVjjltRVN6SQcoSASxf2H2EpgA==
-----END PUBLIC KEY-----
, got -----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYHrc2WIE3apKLmcxlFFHyVQCQZWh
2+al5W/VMlPr3u4EZ/V/GOBm6+Y9gF3Us3twueXYgdYeFo5o7BUn70MPPw==
-----END PUBLIC KEY-----

main.go:69: error during command execution: no matching signatures: error verifying bundle: comparing public key PEMs, expected -----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEheVfGYrVn2mIUQ4cxMJ6x09oXf82
zFEMG++p4q8Mf+y2gp7Ae4oUaXk6Q9V7aVjjltRVN6SQcoSASxf2H2EpgA==
-----END PUBLIC KEY-----
, got -----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYHrc2WIE3apKLmcxlFFHyVQCQZWh
2+al5W/VMlPr3u4EZ/V/GOBm6+Y9gF3Us3twueXYgdYeFo5o7BUn70MPPw==
-----END PUBLIC KEY-----
```

0 comments on commit a9b33e3

Please sign in to comment.