Skip to content

Commit

Permalink
add deployment guide
Browse files Browse the repository at this point in the history
  • Loading branch information
mikhailswift committed Dec 9, 2024
1 parent caf0de1 commit 87248a4
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/verify-licence.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
- name: Check license headers
run: |
set -e
addlicense --check -l apache -c 'The Witness Contributors' --ignore "chart/**" -v *
addlicense --check -l apache -c 'The Witness Contributors' --ignore "chart/**" --ignore "docs/example-vault/**" -v *
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Witness Webhook is configured primarily through a YAML file, with a few environm
| `WITNESS_WEBHOOK_CONFIG_PATH` | `/webhook-config.yaml` | The path to the yaml config file |
| `WITNESS_WEBHOOK_LISTEN_ADDR` | `:8085` | The address the server will listen on |
| `WITNESS_WEBHOOK_ENABLE_TLS` | `false` | If true, witness-webhook will listen with TLS enabled |
| `WITNESS_WEBHOOK_TLS_CERT` | ` ` | Path to the TLS certificate to use |
| `WITNESS_WEBHOOK_TLS_KEY` | ` ` | Path to the TLS key to use |
| `WITNESS_WEBHOOK_TLS_CERT` | `` | Path to the TLS certificate to use |
| `WITNESS_WEBHOOK_TLS_KEY` | `` | Path to the TLS key to use |
| `WITNESS_WEBHOOK_TLS_SKIP_VERIFY` | `false` | If true, disables certificate and host name verification when establishing TLS connections. DO NOT RUN IN PRODUCTION. |

### YAML Config
Expand Down Expand Up @@ -48,3 +48,7 @@ Currently the available webhook handlers are:
| Option | Default Value | Description |
| ------ | ------------- | ----------- |
| `secret-file-path` | | Path to the file containing the secret used to verify webhooks from Github |

## Deploying

Follow the [Deployment Guide](/docs/deployment-guide.md) here for some examples on how to deploy and use `witness-webhook`
70 changes: 70 additions & 0 deletions docs/deployment-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Deploying witness-webhook

witness-webhook includes a Helm chart to help deploy the service. At the core of it, witness-webhook is a simple service that listens for configured webhook events, creates an in-toto attestation describing the captured events, signs the attestation with a configured signer, and then stores the attestation either to a configured directory or to a configured Archivista instance.

witness-webhook is configured via some environment variables for basic service configuration, and a yaml file that configures the different webhooks the service will listen for. witness-webhook will create an endpoint for each configured webhook in this yaml file at the path `/webhook/{webhook-name}`. Each configured webhook has it's own signer configured to support the case where webhooks from different sources may need to be signed differently. For more details on the specific configuration variables and this yaml file, see the README in the root directory.

## Github and Vault

This example will walk through a sample deployment of witness-webhook that listens for events from Github and signs attestations with a Vault transit key with Kubernetes authentication to Vault. This example will use a local minikube instance to deploy witness-webhook into and a local Vault development instance. This example will assume you have the npm, [minikube](https://minikube.sigs.k8s.io/docs/start), [Vault](https://www.markdownguide.org/basic-syntax/), [Helm](https://helm.sh/docs/intro/install), and [Kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) CLI tools installed.

### Setting up minikube

Once minikube is installed, simply running `minikube start` will be enough to bring up a minikube instance sufficient for this example. Your kubecontext should automatically be switched to point to the minikube instance, but just in case or if you switch your kubecontext, running `minikube update-context` will set it back.

Any files referenced in the following steps are available in the docs/example-vault directory, and all commands assume you are running in the docs/example-vault directory.

### Setting up Vault

1. Start the Vault server with `vault server -dev -dev-root-token-id root -dev-listen-address 0.0.0.0:8200 -log-level=debug`
1. Set VAULT_ADDR to point to the local dev server with `export VAULT_ADDR=http://127.0.0.1:8200`
1. Enable kubernetes authentication `vault auth enable kubernetes`
1. Enable the transit secrets engine `vault secrets enable transit`
1. Create a transit key with `vault write transit/keys/testkey type=ecdsa-p521`
1. Create a vault service account for the Token Reviewer: `kubectl create serviceaccount vault-token-reviewer`
1. Apply the cluster role for Token Reivew `kubectl apply -f cluterrole.yaml`
1. Create a token for the Token Reviewer service account `export REVIEWER_TOKEN=$(kubectl create token vault-token-reviewer)`
1. Get the Kubernetes CA `export KUBE_CA=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode)`
1. Get the Kubernetes host `` export KUBE_HOST=`$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.server}')` ``
1. Configure kubernetes auth for Vault `vault write auth/kubernetes/config token_reviewer_jwt="${REVIEWER_TOKEN}" kubernetes_host="${KUBE_HOST}" kubernetes_ca_cert="${KUBE_CA}" issuer="https://kubernetes.default.svc.cluster.local"`
1. Apply a Vault policy allowing access to the transit secret engine `vault write sys/policy/witness-webhook [email protected]`
1. Create a role that will bind to witness-webhook's service account `vault write auth/kubernetes/role/witness-webhook bound_service_account_names="witness-webhook" bound_service_account_namespaces="default" policies="witness-webhook" ttl=5m`

### Deploying witness-webhook

1. Create a service account for witness-webhook `kubectl create service account witness-webhook`
1. Create a secret for the webhook, `echo -n supersecretkey > githubsecret` and `kubectl create secret generic githubwebhooksecret --from-file githubsecret`
1. SSH into minikube to get the IP we'll talk to Vault with `minikube ssh dig +short host.docker.internal`
1. Use the IP address above to modify the values.yaml in the example's directory, updating the `hashivault-addr` variable's value. While here, observe the values.yaml. A few things of note: we are mounting the previously created secret into the pod. This mounted secret is then referred to in the witness-webhook's yaml configuration. We are setting a few global Vault configuration variables with the VAULT_ environment variables.
1. Install the Helm chart `helm install witness-webhook ../../chart -f values.yaml`
1. Port forward to the pod:

```
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=witness-webhook,app.kubernetes.io/instance=witness-webhook" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT
```

1. Use smee.io to setup forwarding to the locally running witness-webhook `npm install -g smee-client` and `smee -t http://localhost:8080/webhook/github` . Make note of the URL smee provides.

### Setting up webhook events from a Github repository

Navigate to a repository of your choice, and enter the Settings tag. From here find the Webhooks section. Add a new webhook.

For the Payload URL, use the URL smee provided to you. It should look similar to <https://smee.io/tjywPLhwk6tJyLus> .

Select application/json as the Content type

For the Secret, insert `supersecretkey`, matching the secret we created earlier.

Select which events you would like to receive.

Once this is setup, try to trigger one of the events.

You can follow the witness-webhook logs with `kubectl logs -f $POD_NAME` and should see something similar to the following if all is successful

```
2024/12/09 23:08:39 attestation stored in archivista for webhook github with gitoid d3b05a8d9b2771b082f845d418936b144adcc8d38b5f5cb10a66e063f6090d5c
```
18 changes: 18 additions & 0 deletions docs/example-vault/ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC7jCCAdagAwIBAgIQLG6VSalCZxOnQLmnZiPYRDANBgkqhkiG9w0BAQsFADAR
MQ8wDQYDVQQKEwZtc3dpZnQwHhcNMjQwODIyMjAxNTAwWhcNMjcwODA3MjAxNTAw
WjARMQ8wDQYDVQQKEwZtc3dpZnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCXEhBPjugNKvAAlaSygh6UNXEmyNlgCBF1Y6c2YloO8SjhArv+H2qzIBWP
QgQVz9RDMWt7oVmPcABeZt1xfcbH4rIZsANf/ymIMdM85L/WurSzaBSgOTUSqKpw
uMCZ1ZLyC+ezekXp6PQIK9R+YDNnl9NYOjk1lpsXv6HrHeCxpiYz45Huyn7h+G4p
uQsqtiG/1POGT0M0HGxSu5lXQkmCr2RGx5f6Y2zbTFN9epqh6LvBRLY3JkIefbnD
A5QR9AIqtiR43dZpx0vgzMzFsOKWXtQdQ0UEIMhabUgG4w6k0F87V8sXTytgUumv
gooNtv1IvZfpv4I1pw5bwOezskhtAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwICrDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRLUF2M68Nn43e5NOU3AfpQo3jisTAN
BgkqhkiG9w0BAQsFAAOCAQEAYSjacIl/TXV6JFSkTGv1SezNlpWOUJHy6qftR7z5
SUxjVcD0ztfKZX4gIvqkHV7xjGbsVo+dJ663G6WI0P1+8ZakINCbEy0HFvdmJ5h9
AXZPxmFGMVhFLDxa+JNWe05s1cTCgHNGWFf+MCxNT77ICoadUdVaVrv3SngVkUDo
2Ihz51aGkiNFvD/ICnzZxKhT1RP8CzQow4UaWC3cN3KetqD+qL/cgOR3BvJLi7DS
+yOgJS1aVSu9w3kW6LU5zs5kmYcAra+NAIA4ZhT4bn+hgVMAYKr3ABg6PLF4bFAO
oh4ZHrAJ03GlsTbL8uVPTorEiovbDpWpNDd+WdD84hYJkQ==
-----END CERTIFICATE-----
13 changes: 13 additions & 0 deletions docs/example-vault/clusterrole.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: role-tokenreview-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: vault-token-reviewer
namespace: default
35 changes: 35 additions & 0 deletions docs/example-vault/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
serviceAccount:
create: false
name: "witness-webhook"

volumes:
- name: githubwebhooksecret
secret:
secretName: githubwebhooksecret

# Additional volumeMounts on the output Deployment definition.
volumeMounts:
- name: githubwebhooksecret
mountPath: /etc/githubwebhooksecret
readonly: true

env:
- name: VAULT_NAMESPACE
value: ADMIN

# witness webhook application specific config
# see README.md section on the YAML config for values here.
witnesswebhook:
archivistaUrl: https://archivista.testifysec.io
webhooks:
github:
type: "github"
signer: "kms"
signerOptions:
ref: "hashivault://testkey"
hashivault-addr: http://192.168.65.254:8200
hashivault-auth-method: kubernetes
hashivault-auth-mount-path: kubernetes
hashivault-role: witness-webhook
options:
secret-file-path: "/etc/githubwebhooksecret/githubsecret"
101 changes: 101 additions & 0 deletions docs/example-vault/vaultpolicy.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Allow tokens to look up their own properties
path "auth/token/lookup-self" {
capabilities = ["read"]
}

# Allow tokens to renew themselves
path "auth/token/renew-self" {
capabilities = ["update"]
}

# Allow tokens to revoke themselves
path "auth/token/revoke-self" {
capabilities = ["update"]
}

# Allow a token to look up its own capabilities on a path
path "sys/capabilities-self" {
capabilities = ["update"]
}

# Allow a token to look up its own entity by id or name
path "identity/entity/id/{{identity.entity.id}}" {
capabilities = ["read"]
}
path "identity/entity/name/{{identity.entity.name}}" {
capabilities = ["read"]
}


# Allow a token to look up its resultant ACL from all policies. This is useful
# for UIs. It is an internal path because the format may change at any time
# based on how the internal ACL features and capabilities change.
path "sys/internal/ui/resultant-acl" {
capabilities = ["read"]
}

# Allow a token to renew a lease via lease_id in the request body; old path for
# old clients, new path for newer
path "sys/renew" {
capabilities = ["update"]
}
path "sys/leases/renew" {
capabilities = ["update"]
}

# Allow looking up lease properties. This requires knowing the lease ID ahead
# of time and does not divulge any sensitive information.
path "sys/leases/lookup" {
capabilities = ["update"]
}

# Allow a token to manage its own cubbyhole
path "cubbyhole/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}

# Allow a token to wrap arbitrary values in a response-wrapping token
path "sys/wrapping/wrap" {
capabilities = ["update"]
}

# Allow a token to look up the creation time and TTL of a given
# response-wrapping token
path "sys/wrapping/lookup" {
capabilities = ["update"]
}

# Allow a token to unwrap a response-wrapping token. This is a convenience to
# avoid client token swapping since this is also part of the response wrapping
# policy.
path "sys/wrapping/unwrap" {
capabilities = ["update"]
}

# Allow general purpose tools
path "sys/tools/hash" {
capabilities = ["update"]
}
path "sys/tools/hash/*" {
capabilities = ["update"]
}

# Allow checking the status of a Control Group request if the user has the
# accessor
path "sys/control-group/request" {
capabilities = ["update"]
}

# Allow a token to make requests to the Authorization Endpoint for OIDC providers.
path "identity/oidc/provider/+/authorize" {
capabilities = ["read", "update"]
}

# Allow permissions to transit
path "transit/keys/*" {
capabilities = [ "read", "update", "create" ]
}

path "transit/sign/*" {
capabilities = [ "read", "update", "create" ]
}

0 comments on commit 87248a4

Please sign in to comment.