Deployment


Develocity Provenance Governor is provided as a container image that runs on a Kubernetes cluster (recommended) or a local Docker/Kubernetes environment. Make sure you have the prerequisites detailed in Prerequisites before proceeding.

Audience

This guide is written for a Platform / Infrastructure Engineer. It assumes:

  • Basic familiarity with Kubernetes (namespaces, secrets, configmaps, deployments, ingress)

  • Ability to obtain a Develocity license file (develocity.license)

  • (Optional) Ability to obtain access tokens/keys for Develocity and Artifactory instances

  • Access to a DNS domain (optional, for public HTTPS ingress)

Quickstart

Want to get started quickly with a local k3d cluster and basic HTTP ingress?

See the Quickstart Guide for condensed setup instructions.

The quickstart will guide you through:

  • Creating a local k3d cluster

  • Deploying Develocity Provenance Governor with basic HTTP ingress

  • Verifying the deployment

After completing the quickstart, return to the sections below to configure additional features like authentication, integrations, and policies.

Deployment Flow Overview

The recommended order is:

  1. Choose / create a Kubernetes cluster (local k3d or existing)

  2. Create namespace + required secrets (registry + license)

  3. Configure Ingress (HTTP, then HTTPS + cert-manager) - Optional

  4. Deploy the core workload (ServiceAccount, Services, Deployment, NetworkPolicy)

  5. Verify rollout & logs

  6. Create placeholder Secrets/ConfigMaps for dynamic configuration (secrets, properties, policies)

  7. Add integrations (Develocity instances, Artifactory instances)

  8. Add signing keys

  9. Enable authentication (Basic and/or OIDC)

  10. Define policies (AccessControl manifests)

  11. Roll out config changes as needed

  12. Troubleshoot rollout issues

Estimated setup time:

  • Local k3d (Quickstart): 15-30 minutes

  • Production setup with all integrations: 2-4 hours (depending on external service coordination and certificate setup)

Select Kubernetes Distribution

Before proceeding ensure access to a Kubernetes cluster has been provided, otherwise a local k3d cluster is also supported.

k3d

Install k3d
brew install k3d
Create k3d cluster (port 80 exposed for ingress)
k3d cluster create --port "80:80@loadbalancer"

Prepare the Kubernetes Namespace and Required Secrets

You must create a Kubernetes namespace and the secrets needed for the application to start.

Create Kubernetes Namespace

Namespace that the Develocity Provenance Governor will be deployed to.
kubectl create namespace develocity-provenance-governor

Docker Registry Secret (Required)

Authenticate to registry.gradle.com to pull the product image.

kubectl create secret docker-registry registry-secret \
  --namespace develocity-provenance-governor \
  --docker-server=https://registry.gradle.com \
  --docker-username=user \
  --docker-password=$(cat ./develocity.license)

Develocity License Secret (Required)

A Develocity license is required for the deployment to be successful.

kubectl create secret generic license \
  --namespace develocity-provenance-governor \
  --from-file=develocity.license=./develocity.license

Ingress (Optional)

No default ingress is provided. Choose what aligns with organizational standards. Below examples cover:

  • Local development (nip.io hostname)

  • HTTPS with cert-manager & Let’s Encrypt

Create Ingress Manifest
kubectl --namespace develocity-provenance-governor apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api.127.0.0.1.nip.io
spec:
  rules:
    - host: api.127.0.0.1.nip.io
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-http
                port:
                  number: 80
EOF
Verify Ingress Resource
kubectl get ingress api.127.0.0.1.nip.io --namespace develocity-provenance-governor
Expected Response
NAME   CLASS     HOSTS                  ADDRESS      PORTS   AGE
http   traefik   api.127.0.0.1.nip.io   172.18.0.3   80      15s
Verify Route
curl api.127.0.0.1.nip.io -i
Expected Response
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
Www-Authenticate: Basic realm="Realm"
...

Ingress with cert-manager

Alternative, ingress manifest using cert-manager, nginx, and signed certificate from Let’s Encrypt. The ingress resource, can be used to expose the api service outside the cluster. Modify the provided manifest to reflect the domain that you control paying close attention to tls[0].hosts[0] and rules[0].host.

kubectl --namespace develocity-provenance-governor apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: https
spec:
  tls:
  - hosts:
    - provenance-governor.example.com
    secretName: https-api-tls
  rules:
  - host: provenance-governor.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-http
            port:
              number: 80
EOF

At this point, the ingress controller might use a self-signed certificate provided as a default.

Verify Ingress Resource
kubectl get ingress https --namespace develocity-provenance-governor
Expected Response
NAME   CLASS     HOSTS                  ADDRESS      PORTS   AGE
https   traefik   provenance-governor.example.com   xxx.xxx.xx.x   80, 443      15s

If not already deployed, install cert-manager

Create an Issuer
kubectl --namespace develocity-provenance-governor create --edit -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: lets-encrypt
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: user@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: lets-encrypt
    # Enable the HTTP-01 challenge provider
    solvers:
      - http01:
          ingress:
            ingressClassName: nginx
EOF
This will create a certificate issuer using the Production Instance of Let’s Encrypt. Edit accordingly based on desired certificate issuer implementation. If using Let’s Encrypt, ensure the ingress is publicly accessible and can handle a http01 challenge provider request to complete certificate issuance. Also, be sure to update the email address.
Verify the Issuer
kubectl describe issuer lets-encrypt \
  --namespace develocity-provenance-governor

Detailed issuer information should be returned along with Status.Status: True and Status.Type: Ready.

Edit the https ingress resource to use the lets-encrypt issuer instead of the self signed certificate issuer.

Edit ingress resource
kubectl edit ingress https \
  --namespace develocity-provenance-governor
Add cert-manager.io/issuer: lets-encrypt to annotations:
metadata:
  annotations:
    cert-manager.io/issuer: lets-encrypt
Verify Certificate Issued
$ kubectl get certificate \
  --namespace develocity-provenance-governor

NAME            READY   SECRET          AGE
https-api-tls   True    https-api-tls   2m31s
Verify Https Endpoint

$ curl https://provenance-governor.example.com -i HTTP/2 401 …​

In this example, the request to https://provenance-governor.example.com returns a 401 Unauthorized status code because no credentials were provided. This confirms that the Ingress is correctly routing traffic to the service and that the service is up and running.

To verify the service health:

curl https://provenance-governor.example.com/readyz -i

No SSL negotiation exceptions should be thrown and a 401 should be returned.

Deploy Core Components

Apply the workload manifests. (See Quickstart)

Download the manifest.yaml file.

kubectl --namespace develocity-provenance-governor apply -f manifest.yaml
Verify Rollout
kubectl rollout status deployment/api \
  --timeout=90s \
  --namespace develocity-provenance-governor

Expected output: deployment "api" successfully rolled out. If rollout fails:

  • Verify registry-secret credentials and image digest/tag

  • Verify license secret presence and correct file content

Verify Logs
kubectl logs deployment/api \
  --namespace develocity-provenance-governor | grep -i license
Sample lines
Develocity license enabled, with license [...]
Started ProvenanceGovernor in ...

Create Placeholders for Dynamic Configuration (Optional but Recommended)

The Deployment mounts (optionally) these resources:

Resource

Kind

Purpose

Required

Mounted Path

license

Secret

Develocity product license

Yes

/workspace/config/license

secrets

Secret

Sensitive values (access tokens, private keys)

No

/workspace/config/secrets

properties

ConfigMap

Non-sensitive configuration (URIs, public keys)

No

/workspace/config/properties

policies

ConfigMap

Policy manifests

No

/workspace/config/policies

Create empty resources to prepare for configuration:

kubectl create secret generic secrets --namespace develocity-provenance-governor || true
kubectl create configmap properties --namespace develocity-provenance-governor || true
kubectl create configmap policies --namespace develocity-provenance-governor || true

Configure Develocity Instances (Optional)

Use one or more Develocity instances as attestation data sources.

Key patterns:

  • Secret: develocity.instances.<NAME>.access-key

  • ConfigMap: develocity.instances.<NAME>.uri

<NAME> must be alphanumeric plus dashes or underscores.

Edit Secret
kubectl edit secret secrets --namespace develocity-provenance-governor

Add access key (use stringData: when adding new values):

stringData:
  develocity.instances.MY_INSTANCE.access-key: my-access-key-for-develocity
Edit ConfigMap
kubectl edit configmap properties --namespace develocity-provenance-governor

Add URI:

data:
  develocity.instances.MY_INSTANCE.uri: https://develocity.example.com

Rollout & Verify:

kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl rollout status deployment/api --namespace develocity-provenance-governor --timeout=90s
kubectl logs deployment/api --namespace develocity-provenance-governor | grep -i "Develocity support enabled"

Expected log snippet:

Develocity support enabled, for instance [MY_INSTANCE:https://develocity.example.com]

Troubleshooting: Repeated Retrying [n/10] request …​ indicates connectivity or credential issues.

Configure Artifactory Instances (Optional)

Used to publish attestation data.

Key patterns:

  • Secret: artifactory.instances.<NAME>.access-token (token preferred over legacy key)

  • ConfigMap: artifactory.instances.<NAME>.uri

Edit Secret
kubectl edit secret secrets --namespace develocity-provenance-governor

Add token:

stringData:
  artifactory.instances.MY_ARTIFACTORY.access-token: my-access-token-for-artifactory
Edit ConfigMap
kubectl edit configmap properties --namespace develocity-provenance-governor

Add URI:

data:
  artifactory.instances.MY_ARTIFACTORY.uri: https://artifactory.example.com

Rollout & Verify:

kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl rollout status deployment/api --namespace develocity-provenance-governor --timeout=90s
kubectl logs deployment/api --namespace develocity-provenance-governor | grep -i "Artifactory support enabled"

Expected log snippet:

Artifactory support enabled, for instance [MY_ARTIFACTORY:https://artifactory.example.com]

Configure Signing Keys (Optional but Recommended for Attestations)

Attestations are wrapped in a Dead Simple Signing Envelope (DSSE) signed by a key pair.

Required key property patterns:

  • Secret (private key, base64 PEM): signing.key.<FRIENDLY_KEY_NAME>.private-pem

  • ConfigMap (public key PEM block): signing.key.<FRIENDLY_KEY_NAME>.public-pem

Choose a naming convention like <ORG_OR_PRODUCT>_YYYY-MM-DD for rotation clarity.

Create Ed25519 Key Pair

Recommended (128-bit security, small key sizes/signatures).

openssl genpkey \
  -algorithm Ed25519 \
  -out private-key.pem
Use OpenSSL to create a Public Key based on the Private Key
openssl pkey \
  -in private-key.pem \
  -pubout \
  -out public-key.pem
Edit Secrets
kubectl edit secret secrets \
  --namespace develocity-provenance-governor

Base64 and add private key (Secret):

base64 -i private-key.pem | pbcopy
kubectl edit secret secrets --namespace develocity-provenance-governor

Paste under data: (Kubernetes will not modify pasted base64):

data:
  signing.key.FRIENDLY_KEY_NAME.private-pem: <PASTE_BASE64_PRIVATE_KEY>
Add public key (ConfigMap):
cat public-key.pem | sed 's/^/    /' | pbcopy
kubectl edit configmap properties --namespace develocity-provenance-governor

Paste under data::

data:
  # PASTE THE PUBLIC KEY BLOCK HERE FROM CLIPBOARD
  signing.key.FRIENDLY_KEY_NAME.public-pem: |
    -----BEGIN PUBLIC KEY-----
    ...
    -----END PUBLIC KEY-----

Rollout & Verify:

kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl logs deployment/api --namespace develocity-provenance-governor | grep -i "Signature support enabled"

Expected log:

Signature support enabled, for key pair [name:FRIENDLY_KEY_NAME:keyid:XXXXXX:signing-algorithm:ed25519]

Key ID is a 6-character abbreviation of the SHA-256 digest of the public key.

Other Supported Algorithms

Elliptic Curve (ECDSA) and RSA are also supported. Substitute commands below; follow the same secret/configmap procedure.

Elliptic Curve (prime256v1)

openssl ecparam -name prime256v1 -genkey -noout -out ec_private.key
openssl pkcs8 -topk8 -inform PEM -in ec_private.key -outform PEM -nocrypt -out private-key.pem
openssl ec -in ec_private.key -pubout -out public-key.pem

Expected log algorithm: SHA256withECDSA.

RSA (2048)

openssl genrsa -out private-key.pem 2048
openssl rsa -in private-key.pem -pubout -out public-key.pem

Expected log algorithm: SHA256withRSA.

Authentication (Optional)

Supported schemes:

Enable Basic Authentication

Add identities under:

  • Secret key pattern: basic.identities.<NAME>

<NAME> is a human-friendly identifier. No default credentials exist.

kubectl edit secret secrets --namespace develocity-provenance-governor
Add a new Basic Identity
stringData:
  basic.identities.some-user: "\{noop\}some-pass"

Recommendation: Replace {noop} with {bcrypt} and supply a bcrypt-hashed password.

Rollout Deployment
kubectl rollout restart deployment/api \
  --namespace develocity-provenance-governor
Verify Basic Authentication Enabled
kubectl logs deployment/api \
  --namespace develocity-provenance-governor |
  grep -i "Basic Identity support"
Expected Log Line
Basic Identity support enabled, for identity [some-user]

Enable OIDC Authentication

OIDC Providers are dynamically discovered based on token issuers specified in policies. See the Policies section for examples.

Policies (Optional)

Policies are YAML documents stored inside the policies ConfigMap. Each key corresponds to a file-style name ending with .yaml.

Access Control Policies

Define who can do what on which resources.

identityMatchingStrategy supported:

  • withBasicIdentity – must match a key under basic.identities.<NAME> in secrets

  • withOidc – relies on issuer discovery; ensure network accessibility

canPerform supported actions: * publish-attestations - publish DSSE-wrapped attestations to an Attestation Store (e.g., Artifactory) * publish-policy-scans - publish Policy Scan™ results to an Attestation Store

withResources supported patterns:

  • pkg:pkg-type/pkg-namespace/pkg-name@pkg-vesion - specific Package URL pattern to match or use wildcards:

    • pkg:maven/* - all Maven packages

    • pkg:oci/* - all OCI packages (container images)

    • pkg:maven/org.example/@ - all Maven packages in org.example namespace and any version

    • pkg:maven/org.example/my-app@1.0.0 - specific Maven package

    • pkg:oci/image-name@v1* - specific OCI image with wildcard version

  • *:REPLACE_WITH_DV_INSTANCE_NAME/* - allow to read build scans from the Develocity Instance to source data for attestations.

  • *:REPLACE_WITH_ARTIFACTORY_INSTANCE_NAME/* - allow to publish attestations to the Artifactory Instance. Replace * with the repository name in artifactory to restrict access further.

  • *:*/* - allows authenticated identity access to all resources (not recommended for production use)

Basic Identity Policy Example

kubectl edit configmap policies --namespace develocity-provenance-governor
Add basic-identity-some-user-full-access.yaml policy
data:
  basic-identity-some-user-full-access.yaml: |
    apiVersion: policy.gradle.com/v1
    kind: AccessControl
    metadata:
      name: basic-identity-some-user-full-access
    spec:
      identityMatchingStrategy:
        withBasicIdentity:
          - withName: "some-user"
      canPerform:
        - publish-attestations
        - publish-policy-scans
      withResources:
        - "*:*/*"

OIDC Policy Example (GitHub Actions)

kubectl edit configmap policies --namespace develocity-provenance-governor
Add oidc-github-action-full-access.yaml policy
data:
  oidc-github-action-full-access.yaml: |
    apiVersion: policy.gradle.com/v1
    kind: AccessControl
    metadata:
      name: oidc-github-action-full-access
    spec:
      identityMatchingStrategy:
        withOidc:
          - fromIssuerUri: https://token.actions.githubusercontent.com
            withClaims:
              job_workflow_ref: org/automation-repo/.github/workflows/build-image.yml@*
      canPerform:
        - publish-attestations
        - publish-policy-scans
      withResources:
        - "*:*/*"

Public Key Verification Policy Example

kubectl edit configmap policies --namespace develocity-provenance-governor
Add public-key-verification-policy.yaml policy
data:
  public-key-verification-policy.yaml: |
    apiVersion: policy.gradle.com/v1
    kind: TrustedPublicKeys
    metadata:
      name: public-keys
    spec:
      resultsLabels: []
      description: Public keys trusted for attestations.
      remediation: Update the list of trusted public keys to ensure only verified attestations are accepted.
      keys:
        DEPLOYMENT_KEY_2025_10_01:
          pem: |
            -----BEGIN PUBLIC KEY-----
            ....
            -----END PUBLIC KEY-----

Replace DEPLOYMENT_KEY_2025_10_01 and the PEM block with your actual trusted public keys, for example the ones used to sign attestations.

Rollout Deployment
kubectl rollout restart deployment/api \
    --namespace develocity-provenance-governor
kubectl rollout status deployment/api \
    --namespace develocity-provenance-governor \
    --timeout=90s
Verify Policies Loaded
kubectl logs deployment/api \
    --namespace develocity-provenance-governor |
    grep -i "Loading Policy Resource from file"
Expected Log Lines
Loading Policy Resource from file [/workspace/config/policies/public-key-verification-policy.yaml]

Troubleshooting Deployment Rollouts

Common rollout hang:

Waiting for deployment "api" rollout to finish: 1 old replicas are pending termination...
error: timed out waiting for the condition

Inspect pods:

kubectl get pods --namespace develocity-provenance-governor

Identify failing pod (e.g., CrashLoopBackOff) and fetch logs:

kubectl logs api-<POD_ID> --namespace develocity-provenance-governor

Example configuration error:

***************************
APPLICATION FAILED TO START
***************************

Failed to bind properties under 'artifactory.instances.INSTANCE_NAME_GOES_HERE' ... Reason: java.lang.IllegalArgumentException: uri must not be null

Remediation:

  • Missing URI – edit properties ConfigMap key artifactory.instances.<NAME>.uri

  • Missing token – edit secrets key artifactory.instances.<NAME>.access-token

After fixing, restart:

kubectl rollout restart deployment/api --namespace develocity-provenance-governor
kubectl rollout status deployment/api --namespace develocity-provenance-governor --timeout=90s

Verification and Next Steps

After completing the deployment, verify that Develocity Provenance Governor is running correctly:

  1. Check Pod Status

    kubectl get pods -n develocity-provenance-governor

    You should see the api pod in Running state with 1/1 ready.

  2. Check Application Logs

    kubectl logs deployment/api -n develocity-provenance-governor --tail=50

    Look for messages indicating: License loaded successfully Integrations enabled (e.g., "Develocity support enabled", "Artifactory support enabled") Policies loaded (if configured) No error messages

  3. Test API Accessibility

    curl -i http://your-provenance-governor-hostname

    You should receive a 401 Unauthorized response, which confirms the application is running and authentication is required.

    The actuator endpoints (health, readiness, liveness, prometheus) are exposed on port 9090 and not accessible through the public ingress. Develocity Provenance Governor also exposes /livez and /readyz endpoints on the main application port for health checking when Kubernetes probes are enabled.

  4. Verify Integration Configuration

    Check that your configured integrations were loaded:

    kubectl logs deployment/api -n develocity-provenance-governor | grep "support enabled"

Successfully deployed? If all verification steps passed and you’re ready to start using Develocity Provenance Governor, proceed to Publishing Attestations to learn how to publish attestations and evaluate policies.

What to Do Next:

  • Configure Your First Integration - If you haven’t already, set up connections to Develocity and Artifactory. See Application Configuration.

  • Set Up Authentication - Configure access control policies to secure your API. See Access Control.

  • Write Your First Policy - Define policies for your software supply chain governance. See Writing Policies.

  • Publish Test Attestations - Try publishing attestations for a test package. See Publishing Attestations.

  • Integrate with CI/CD - Add Develocity Provenance Governor to your build and deployment pipelines. See GitHub Actions or CI/CD Integration.

If you encounter issues, consult the Troubleshooting section.

Summary Cheat Sheet

Integration

Secret Key Pattern

ConfigMap Key Pattern

Mandatory

Notes

License

(file) develocity.license

n/a

Yes

Provided via license secret

Registry Auth

.dockerconfigjson

n/a

Yes

JSON auth file for image pulls

Develocity Instance

develocity.instances.<NAME>.access-key

develocity.instances.<NAME>.uri

No

Multiple supported

Artifactory Instance

artifactory.instances.<NAME>.access-token

artifactory.instances.<NAME>.uri

No

Token preferred

Signing Key (Private)

signing.key.<KEY>.private-pem

n/a

No

Base64 PEM

Signing Key (Public)

n/a

signing.key.<KEY>.public-pem

No

PEM block

Basic Identity

basic.identities.<NAME>

n/a

No

{bcrypt} recommended

Policies

n/a

<policy-name>.yaml in policies ConfigMap

No

AccessControl docs