Skip to content

[SECURESIGN-1401] Implement Fulcio cert rotation scenario #2970

[SECURESIGN-1401] Implement Fulcio cert rotation scenario

[SECURESIGN-1401] Implement Fulcio cert rotation scenario #2970

Workflow file for this run

name: Validate SecureSign
on:
workflow_dispatch:
push:
branches: [ "main", "release*" ]
tags: [ "*" ]
pull_request:
branches: [ "main", "release*" ]
env:
GO_VERSION: 1.21
IMG: ttl.sh/securesign/secure-sign-operator-${{github.run_number}}:1h
BUNDLE_IMG: ttl.sh/securesign/bundle-secure-sign-${{github.run_number}}:1h
CATALOG_IMG: ttl.sh/securesign/catalog-${{github.run_number}}:1h
jobs:
build-operator:
name: Build-operator
runs-on: ubuntu-20.04
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Replace images
run: make dev-images && cat internal/controller/constants/images.go
- name: Build operator container
run: make docker-build docker-push
build-bundle:
name: Build-bundle-image
runs-on: ubuntu-20.04
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Replace images
run: make dev-images && cat internal/controller/constants/images.go
- name: Build operator bundle
run: make bundle bundle-build bundle-push
build-fbc:
name: Build-fbc
runs-on: ubuntu-20.04
needs: build-bundle
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Log in to registry.redhat.io
uses: redhat-actions/podman-login@9184318aae1ee5034fbfbacc0388acf12669171f # v1
with:
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
registry: registry.redhat.io
auth_file_path: /tmp/config.json
- name: Install OPM
run: |
make opm
echo "OPM=${{ github.workspace }}/bin/opm" >> $GITHUB_ENV
- name: Checkout FBC source
uses: actions/checkout@v4
with:
repository: "securesign/fbc"
path: fbc
- name: Build catalog
run: |
cd fbc
chmod +x ./generate-fbc.sh && OPM_CMD=${{ env.OPM }} ./generate-fbc.sh --init-basic v4.14 jq
cat << EOF >> v4.14/graph.json
{
"schema": "olm.bundle",
"image": "$BUNDLE_IMG"
}
EOF
#TODO: versions needs to be maintained - try to eliminate
cat <<< $(jq 'select(.schema == "olm.channel" and .name == "stable").entries += [{"name":"rhtas-operator.v1.1.0", "replaces": "rhtas-operator.v1.0.2"}]' v4.14/graph.json) > v4.14/graph.json
cat v4.14/graph.json
${{ env.OPM }} alpha render-template basic v4.14/graph.json > v4.14/catalog/rhtas-operator/catalog.json
${{ env.OPM }} validate v4.14/catalog/rhtas-operator
docker build v4.14 -f v4.14/catalog.Dockerfile -t $CATALOG_IMG
docker push $CATALOG_IMG
test-kind:
name: Test kind deployment
runs-on: ubuntu-20.04
needs: build-operator
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Log in to registry.redhat.io
uses: redhat-actions/podman-login@9184318aae1ee5034fbfbacc0388acf12669171f # v1
with:
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
registry: registry.redhat.io
auth_file_path: /tmp/config.json
# install tuftool
- name: Checkout tough source
uses: actions/checkout@v4
with:
repository: "securesign/tough"
path: tough
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
- run: cd tough && cargo build --release && echo "$PWD/target/release" >> $GITHUB_PATH
- name: Install Cluster
uses: container-tools/[email protected]
with:
version: v0.24.0
node_image: kindest/node:v1.27.17@sha256:3fd82731af34efe19cd54ea5c25e882985bafa2c9baefe14f8deab1737d9fabe
cpu: 3
registry: false
config: ./ci/config.yaml
- name: Install Ingress
run: |
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=90s
- name: Install prometheus
run: |
LATEST=$(curl -s https://api.github.com/repos/prometheus-operator/prometheus-operator/releases/latest | jq -cr .tag_name)
curl -sL https://github.com/prometheus-operator/prometheus-operator/releases/download/${LATEST}/bundle.yaml | kubectl create -f -
kubectl wait --for=condition=Ready pods -l app.kubernetes.io/name=prometheus-operator -n default
- name: Deploy operator container
env:
OPENSHIFT: false
run: make deploy
- name: Wait for operator to be ready
run: |
kubectl wait --for=condition=available deployment/rhtas-operator-controller-manager --timeout=120s -n openshift-rhtas-operator
- name: Install Keycloak
run: |
#install OLM
kubectl create -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.25.0/crds.yaml
# wait for a while to be sure CRDs are installed
sleep 1
kubectl create -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.25.0/olm.yaml
kubectl create --kustomize ci/keycloak/operator/overlay/kind
until [ ! -z "$(kubectl get pod -l name=keycloak-operator -n keycloak-system 2>/dev/null)" ]
do
echo "Waiting for keycloak operator. Pods in keycloak-system namespace:"
kubectl get pods -n keycloak-system
sleep 10
done
kubectl create --kustomize ci/keycloak/resources/overlay/kind
until [[ $( oc get keycloak keycloak -o jsonpath='{.status.ready}' -n keycloak-system 2>/dev/null) == "true" ]]
do
printf "Waiting for keycloak deployment. \n Keycloak ready: %s\n" $(oc get keycloak keycloak -o jsonpath='{.status.ready}' -n keycloak-system)
sleep 10
done
# HACK - expose keycloak under the same name as the internal SVC has so it will be accessible:
# - within the cluster (where the localhost does not work)
# - outside the cluster (resolved from /etc/hosts and redirect to the localhost)
kubectl create -n keycloak-system -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: keycloak
spec:
rules:
- host: keycloak-internal.keycloak-system.svc
http:
paths:
- backend:
service:
name: keycloak-internal
port:
number: 80
path: /
pathType: Prefix
EOF
shell: bash
- name: Add service hosts to /etc/hosts
run: |
sudo echo "127.0.0.1 fulcio-server.local tuf.local rekor-server.local keycloak-internal.keycloak-system.svc rekor-search-ui.local cli-server.local tsa-server.local" | sudo tee -a /etc/hosts
- name: Install cosign
run: go install github.com/sigstore/cosign/v2/cmd/[email protected]
- name: Replace images
run: make dev-images && cat internal/controller/constants/images.go
- name: Run tests
run: make test-e2e
- name: Archive test artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: test-kind
path: test/**/k8s-dump-*.tar.gz
- name: dump the logs of the operator
run: kubectl logs -n openshift-rhtas-operator deployment/rhtas-operator-controller-manager
if: always()
test-upgrade:
name: Test upgrade operator
runs-on: ubuntu-20.04
needs:
- build-operator
- build-bundle
- build-fbc
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
tool-cache: true
- name: Checkout source
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Log in to registry.redhat.io
uses: redhat-actions/podman-login@9184318aae1ee5034fbfbacc0388acf12669171f # v1
with:
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
registry: registry.redhat.io
auth_file_path: /tmp/config.json
- name: Image prune
run: docker image prune -af
- name: Install Cluster
uses: container-tools/[email protected]
with:
version: v0.20.0
node_image: kindest/node:v1.26.6@sha256:6e2d8b28a5b601defe327b98bd1c2d1930b49e5d8c512e1895099e4504007adb
cpu: 3
registry: false
config: ./ci/config.yaml
- name: Configure cluster
run: |
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=90s
#install Prometheus
LATEST=$(curl -s https://api.github.com/repos/prometheus-operator/prometheus-operator/releases/latest | jq -cr .tag_name)
curl -sL https://github.com/prometheus-operator/prometheus-operator/releases/download/${LATEST}/bundle.yaml | kubectl create -f -
kubectl wait --for=condition=Ready pods -l app.kubernetes.io/name=prometheus-operator -n default
#install OLM
kubectl create -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.25.0/crds.yaml
# wait for a while to be sure CRDs are installed
sleep 1
kubectl create -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.25.0/olm.yaml
kubectl create --kustomize ci/keycloak/operator/overlay/kind
until [ ! -z "$(kubectl get pod -l name=keycloak-operator -n keycloak-system 2>/dev/null)" ]
do
echo "Waiting for keycloak operator. Pods in keycloak-system namespace:"
kubectl get pods -n keycloak-system
sleep 10
done
kubectl create --kustomize ci/keycloak/resources/overlay/kind
until [[ $( oc get keycloak keycloak -o jsonpath='{.status.ready}' -n keycloak-system 2>/dev/null) == "true" ]]
do
printf "Waiting for keycloak deployment. \n Keycloak ready: %s\n" $(oc get keycloak keycloak -o jsonpath='{.status.ready}' -n keycloak-system)
sleep 10
done
# HACK - expose keycloak under the same name as the internal SVC has so it will be accessible:
# - within the cluster (where the localhost does not work)
# - outside the cluster (resolved from /etc/hosts and redirect to the localhost)
kubectl create -n keycloak-system -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: keycloak
spec:
rules:
- host: keycloak-internal.keycloak-system.svc
http:
paths:
- backend:
service:
name: keycloak-internal
port:
number: 80
path: /
pathType: Prefix
EOF
shell: bash
- name: Add service hosts to /etc/hosts
run: |
sudo echo "127.0.0.1 fulcio-server.local tuf.local rekor-server.local keycloak-internal.keycloak-system.svc rekor-search-ui.local cli-server.local tsa-server.local" | sudo tee -a /etc/hosts
- name: Install cosign
run: go install github.com/sigstore/cosign/v2/cmd/[email protected]
- name: Replace images
run: make dev-images && cat internal/controller/constants/images.go
- name: Run tests
env:
TEST_BASE_CATALOG: registry.redhat.io/redhat/redhat-operator-index:v4.14
TEST_TARGET_CATALOG: ${{ env.CATALOG_IMG }}
OPENSHIFT: false
run: go test -p 1 ./test/e2e/... -tags=upgrade -timeout 20m
- name: Archive test artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: test-upgrade
path: test/**/k8s-dump-*.tar.gz
test-custom-install:
name: Test with custom operator installation
runs-on: ubuntu-20.04
needs:
- build-operator
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
tool-cache: true
- name: Checkout source
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Log in to registry.redhat.io
uses: redhat-actions/podman-login@9184318aae1ee5034fbfbacc0388acf12669171f # v1
with:
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
registry: registry.redhat.io
auth_file_path: /tmp/config.json
- name: Image prune
run: docker image prune -af
- name: Install Cluster
uses: container-tools/[email protected]
with:
version: v0.20.0
node_image: kindest/node:v1.26.6@sha256:6e2d8b28a5b601defe327b98bd1c2d1930b49e5d8c512e1895099e4504007adb
cpu: 3
registry: false
config: ./ci/config.yaml
- name: Configure cluster
run: |
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=90s
shell: bash
- name: Add service hosts to /etc/hosts
run: |
sudo echo "127.0.0.1 fulcio-server.local tuf.local rekor-server.local rekor-search-ui.local cli-server.local" | sudo tee -a /etc/hosts
- name: Replace images
run: make dev-images && cat internal/controller/constants/images.go
- name: Run tests
env:
TEST_MANAGER_IMAGE: ${{ env.IMG }}
OPENSHIFT: false
run: make install && go test ./test/e2e/... -tags=custom_install -p 1 -timeout 20m
- name: Archive test artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: test-custom-install
path: test/**/k8s-dump-*.tar.gz
test-eks:
name: Test EKS deployment
runs-on: ubuntu-20.04
needs: build-operator
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
env:
AWS_REGION: us-east-2
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
TEST_NAMESPACE: test
OIDC_ISSUER_URL: ${{ secrets.testing_keycloak }}
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Install eksctl
run: |
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH
curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz
sudo mv /tmp/eksctl /usr/local/bin
- name: Install kubectl
run: |
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH
curl -sLO "https://dl.k8s.io/release/v1.22.0/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin
- name: run eksctl create cluster
run: |
eksctl create cluster --alb-ingress-access --external-dns-access --name rhtas-eks-${GITHUB_RUN_ID} --nodes 1 --node-type m5.xlarge --spot
eksctl utils associate-iam-oidc-provider --region=us-east-2 --cluster=rhtas-eks-${GITHUB_RUN_ID} --approve
eksctl create iamserviceaccount --region us-east-2 --name ebs-csi-controller-sa --namespace kube-system --cluster rhtas-eks-${GITHUB_RUN_ID} --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy --approve --role-only --role-name AmazonEKS_EBS_CSI_DriverRole
eksctl create addon --name aws-ebs-csi-driver --cluster rhtas-eks-${GITHUB_RUN_ID} --service-account-role-arn arn:aws:iam::${{ secrets.AWS }}:role/AmazonEKS_EBS_CSI_DriverRole --force
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/deploy.yaml
kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
- name: Log in to registry.redhat.io
uses: redhat-actions/podman-login@9184318aae1ee5034fbfbacc0388acf12669171f # v1
with:
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
registry: registry.redhat.io
auth_file_path: /tmp/config.json
- name: Create namespace and serviceaccounts with redhat registry login
run: |
kubectl create ns ${{ env.TEST_NAMESPACE }}
kubectl create secret generic redhat-registry -n ${{ env.TEST_NAMESPACE }} --from-file=.dockerconfigjson=/tmp/config.json --type=kubernetes.io/dockerconfigjson
kubectl patch serviceaccount default --type=merge -p '{"imagePullSecrets": [{"name":"redhat-registry"}]}' -n ${{ env.TEST_NAMESPACE }}
for NAME in "fulcio" "ctlog" "trillian" "rekor" "tuf" "tsa"
do
echo """
apiVersion: v1
kind: ServiceAccount
metadata:
name: $NAME
namespace: $TEST_NAMESPACE
imagePullSecrets:
- name: redhat-registry
""" |
kubectl create -f -
done
- name: Deploy operator container
env:
OPENSHIFT: false
run: make deploy
# TODO: deploy ingress and execute e2e
- name: Deploy RTHAS
run: |
sed -i 's|"https://your-oidc-issuer-url"|${{ secrets.testing_keycloak }}|g' config/samples/rhtas_v1alpha1_securesign.yaml
sed -i 's|enabled: true|enabled: false|g' config/samples/rhtas_v1alpha1_securesign.yaml
sed -i 's|rhtas.redhat.com/metrics: "true"|rhtas.redhat.com/metrics: "false"|g' config/samples/rhtas_v1alpha1_securesign.yaml
kubectl apply -f config/samples/rhtas_v1alpha1_securesign.yaml -n ${{ env.TEST_NAMESPACE }}
- name: Until shell script to wait for deployment to be created
run: |
for i in trillian fulcio rekor tuf ctlog timestampAuthority; do
until [ ! -z "$(kubectl get $i -n ${{ env.TEST_NAMESPACE }} 2>/dev/null)" ]
do
echo "Waiting for $i to be created."
sleep 3
done
done
shell: bash
- name: Test components are ready
run: |
kubectl wait --for=condition=ready trillian/securesign-sample -n ${{ env.TEST_NAMESPACE }} --timeout=5m
kubectl wait --for=condition=ready fulcio/securesign-sample -n ${{ env.TEST_NAMESPACE }} --timeout=5m
kubectl wait --for=condition=ready rekor/securesign-sample -n ${{ env.TEST_NAMESPACE }} --timeout=5m
kubectl wait --for=condition=ready ctlog/securesign-sample -n ${{ env.TEST_NAMESPACE }} --timeout=5m
kubectl wait --for=condition=ready tuf/securesign-sample -n ${{ env.TEST_NAMESPACE }} --timeout=5m
kubectl wait --for=condition=ready timestampAuthority/securesign-sample -n ${{ env.TEST_NAMESPACE }} --timeout=5m
- name: Test deployments are ready
run: |
kubectl wait --for=condition=available deployment/trillian-db -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/trillian-logserver -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/trillian-logsigner -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/fulcio-server -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/rekor-server -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/rekor-redis -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/rekor-search-ui -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/tuf -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/ctlog -n ${{ env.TEST_NAMESPACE }}
kubectl wait --for=condition=available deployment/tsa-server -n ${{ env.TEST_NAMESPACE }}
- name: Archive test artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: test-eks
path: test/**/k8s-dump-*.tar.gz
- name: dump the logs of the operator
run: |
kubectl logs -n openshift-rhtas-operator deployment/rhtas-operator-controller-manager
if: always()
- name: delete the cluster
run: eksctl delete cluster --name rhtas-eks-${GITHUB_RUN_ID} --region us-east-2 --wait
if: always()