A simple REST API built in golang
using Labstack's Echo, to demonstrate how integrate CI using,
Optionally as part of the CI the pipeline we can also sign the container image using cosign.
Register yourself for a Free Tier Harness Account at https://app.harness.io.
To configure the Harness CI pipeline for this project you need the following,
- Docker Registry Account Credentials e.g Docker Hub, Quay.io or Harbor
- GitHub Account with a Personal Access Token (PAT) with
admin:repo
anduser
permissions - Private and Public Key pair to sign the built container image
- Kubernetes Cluster
Clone the sources and cd
into it,
git clone https://github.com/kameshsampath/go-hello-world.git && cd "$(basename "$_" .git)"
export TUTORIAL_HOME="$PWD"
Create dontenv
file that we will be using to set/load our environment variables.
cp "$TUTORIAL_HOME/.env.example" "$TUTORIAL_HOME/.env"
Ensure you update REPLACE ME
in "$TUTORIAL_HOME/.env" as per your settings.
Spin up a local Kubernetes cluster where we will deploy the demo application.
"$TUTORIAL_HOME/bin/setup.sh"
Generate private and public key and save them as kubernetes secret my-image-sigs
in namespace cosign-system
,
kubectl create ns cosign-system
cosign generate-key-pair k8s://cosign-system/my-image-sigs
Sign and push the image using Drone CI pipelines,
IMPORTANT: We need to make sure that drone is run with same network as the k3s cluster
$K3D_CLUSTER_NAME
, allowing it to have access to the Cluster kubeconfig
drone exec --env-file=.env --trusted --network="$K3D_CLUSTER_NAME"
Verify image signature,
drone exec --env-file=.env --trusted --pipeline=verify --network="$K3D_CLUSTER_NAME"
Let us use Dsigstore Policy Controller to enforce policy that will allow only signed images to be deployed as part of Kubernetes deployments.
helm repo add sigstore https://sigstore.github.io/helm-charts
helm repo update
Deploy policy-controller
,
helm upgrade --install policy-controller \
-n cosign-system \
--wait \
sigstore/policy-controller
kubectl create secret generic my-verify-key -n cosign-system \
--from-file=cosign.pub="$TUTORIAL_HOME/cosign.pub"
Create a ClusterImagePolicy
that will allow only images signed using keys from my-verify-key
in cosign-system
,
cat <<EOF | kubectl apply -f -
apiVersion: policy.sigstore.dev/v1alpha1
kind: ClusterImagePolicy
metadata:
name: cip-key-secret
namespace: cosign-system
spec:
images:
- glob: "**"
authorities:
- key:
secretRef:
name: my-verify-key
EOF
Let us create a namespace to deploy the application,
kubectl create ns demo-apps
To enforce policy on all applications in this namespace, label the namespace with policy.sigstore.dev/include=true
kubectl label namespace demo-apps policy.sigstore.dev/include=true
Try deploying an image which are not signed using the my-image-sigs
,
kubectl run --image library/nginx -n demo-apps nginx
The deployment should fail with message like,
Error from server (BadRequest): admission webhook "policy.sigstore.dev" denied the request: validation failed: failed policy: cip-key-secret: spec.containers[0].image
index.docker.io/library/nginx@sha256:b8f2383a95879e1ae064940d9a200f67a6c79e710ed82ac42263397367e7cc4e signature key validation failed for authority authority-0 for index.docker.io/library/nginx@sha256:b8f2383a95879e1ae064940d9a200f67a6c79e710ed82ac42263397367e7cc4e: no matching signatures:
Let us now deploy $IMAGE_REGISTRY/$IMAGE_REGISTRY_USERNAME/go-hello-world:$IMAGE_TAG
,
kubectl run --image "$IMAGE_REGISTRY/$IMAGE_REGISTRY_USERNAME/go-hello-world:$IMAGE_TAG" -n demo-apps hello-world
The application should now be created as the image is signed using the keys from my-image-sigs
.
Do a port-forward to application port 8080
,
kubectl port-forward -n demo-apps hello-world 8080:8080
Try calling the API to see a response Hello World!
.
curl http://localhost:8080/
The command should return Hello World!
.
"$TUTORIAL_HOME/bin/cleanup.sh"