Skip to main content

Deploy Trust Domain Servers

You'll use Defakto's Helm chart to deploy Trust Domain Servers in your Kubernetes cluster.

Here is an example of the Helm chart values.yaml file. You should adjust it to your needs.

# SPIRL Trust Domain Server Settings

trustDomainDeployment:
# Trust domain and ID come from the "spirlctl trust-domain register" command.
# You can always find them again using "spirlctl trust-domain list".
trustDomainName: "spirl.example.com"
trustDomainID: "td-diok4t8ahq"

# The trust domain deployment ID is generated from the
# "spirlctl trust-domain deployment create" command.
# You can always find them again using "spirlctl trust-domain deployment list".
id: "tdd-nnlo6k3t3o"

# The "name" corresponds to the value passed to
# "spirlctl trust-domain deployment create" during deployment creation.
# You can always find it again using "spirlctl trust-domain deployment list".
name: "us-west-2"

controlPlane:
auth:
key:
# Trust Domain Key ID from "spirlctl trust-domain register" command output
id: "tdk-jj6lzk6pep"
# Private Key from "spirlctl trust-domain key create" command output
pem: |
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIOeg6Cet10sqNY0dPHV3MXKNyxGgrmKeMN0PZKGS+6iB
-----END PRIVATE KEY-----

Setting up a Load Balancer to the Defakto Trust Domain Server

To connect the Defakto Agents to the Trust Domain Server you will need to set up a domain name for the agent endpoint on the Trust Domain Servers.

Since the Agents use default system trust store to verify TLS certificates, we recommend setting up a Load Balancer for this endpoint. This will also ensure resiliency of the Trust Domain Server.

Before getting started you will need a certificate for the agent endpoint domain name.

Application Load Balancer

You can set up a Kubernetes Ingress with a Load Balancer by enabling the ingress in the Helm Chart values.

Below is an example configuration that sets up an AWS Application Load Balancer:

trustDomainDeployment:
ingress:
enabled: true
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/backend-protocol-version: GRPC
alb.ingress.kubernetes.io/certificate-arn: <YOUR-CERT-ARN>
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
alb.ingress.kubernetes.io/success-codes: "0-99"
alb.ingress.kubernetes.io/target-group-attributes: load_balancing.algorithm.type=least_outstanding_requests
alb.ingress.kubernetes.io/healthcheck-path: /grpc.health.v1.Health/Check
hosts:
- host: <YOUR-CERT-DOMAIN-NAME>
paths:
- path: /
pathType: Prefix
className: alb

Replace the host with a domain name that you own and add the ARN to the certificate for that domain name.

Once the Trust Domain Server has been deployed, get the address of the Ingress:

kubectl get ingress ${YOUR_TD_DEPLOYMENT_ID}-spirl-server-agent -n ${YOUR_TD_DEPLOYMENT_ID}-example

Create a DNS record (Route53, Cloudflare) with your DNS provider to point your agent endpoint domain name to the Ingress address.

Network Load Balancer

To set up an AWS Network Load Balancer you can modify the Kubernetes service for the Trust Domain Server using the Helm Chart Values.

trustDomainDeployment:
service:
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
# TLS termination at NLB
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: <YOUR-CERT-ARN>
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
port: 443
type: LoadBalancer

Add the ARN to the certificate for the domain name you will use for the agent endpoint.

This sets up an NLB with TLS termination, meaning that the connection from the agent to the NLB will use TLS, but the connection from the NLB to the server will be unencrypted.

Once the Trust Domain Server has been deployed, get the "EXTERNAL-IP" of the service:

kubectl get services ${YOUR_TD_DEPLOYMENT_ID}-spirl-server-agent -n ${YOUR_TD_DEPLOYMENT_ID}-example

Create a DNS record (Route53, Cloudflare) with your DNS provider to point your agent endpoint domain name to the "EXTERNAL-IP" address of the service.

Testing the Agent Endpoint

Once you have set up a Load Balancer for the agent endpoint, you can test it using grpcurl

$ grpcurl <agent-endpoint>:443 grpc.health.v1.Health/Check

If everything is setup correctly you should see a response like:

{
"status": "SERVING"
}

TLS on the agent API listener

The agent service is used by agents to access the Defakto server.

In a typical deployment, a load balancer terminates TLS and forwards traffic to the server over an unencrypted last hop. The agent service listener (:8180) therefore accepts plain gRPC by default. You can enable TLS directly on the listener if the last hop must also be encrypted, or if you are using a TCP pass-through load balancer that does not terminate TLS itself. When TLS is enabled on the listener, the TLS session extends from the agent all the way to the server process with no point where traffic is decrypted in between. Key properties:

  • Server-side TLS only. Agents authenticate to the server through agent attestation, not client certificates, so mTLS is not applicable here.
  • The certificate and key are polled from disk every 30 seconds, so rotation takes effect without a restart.
  • When the trustDomainDeployment.tls Helm value is not set, the listener defaults to unencrypted gRPC.

Enable TLS via Helm

Add the following to your values.yaml:

trustDomainDeployment:
tls:
enabled: true
secretName: spirl-server-tls # Kubernetes Secret with tls.crt and tls.key

health:
enabled: true # required when TLS is enabled

Both enabled: true and a non-empty secretName are required. If enabled is true but secretName is empty, the chart fails at render time with:

trustDomainDeployment.tls.secretName is required when trustDomainDeployment.tls.enabled is true

health.enabled: true is also required when TLS is enabled. If TLS is on but the health server is off, the chart fails at render time with:

trustDomainDeployment.tls.enabled with trustDomainDeployment.tls.secretName requires health.enabled=true as a fallback probe endpoint because Kubernetes gRPC probes do not support TLS

Kubernetes readiness probes do not support TLS, so when TLS is active on :8180 the probe falls back to an HTTP health server on :8086 (/ready, /live). The health server runs independently of the gRPC listener and is not affected by TLS.

Create the Kubernetes Secret

Create a Kubernetes Secret in the trust domain deployment namespace with tls.crt and tls.key.

Both entries must be PEM-encoded:

  • tls.crt must contain the full certificate chain: The server (leaf) certificate first, followed by any intermediate CA certificates, concatenated in order. If the intermediates are omitted, agents that do not already trust them cannot build a chain to a trusted root and the connection fails. Tools like Let's Encrypt or certbot produce both a leaf-only file and a full-chain file (often fullchain.pem). Use the full-chain file. The root CA certificate does not need to be included.
  • tls.key must contain the PEM-encoded private key that matches the leaf certificate.

The certificate must not be expired. The server rejects an expired certificate at load time.

Manually:

kubectl create secret tls spirl-server-tls \
--cert=server.crt \
--key=server.key \
--namespace=<trust-domain-deployment-id>

cert-manager: Create a Certificate resource targeting the same secret name. cert-manager rotates the secret automatically; the server picks up the new certificate with no restart required. See the cert-manager Certificate documentation.

AWS ACM and external-secrets: Use an ExternalSecret of type kubernetes.io/tls that populates tls.crt and tls.key from ACM. See the external-secrets ExternalSecret documentation.

Certificate rotation

The server polls the certificate and key files every 30 seconds. When the file content changes, the in-memory certificate is swapped atomically with no restart required. When cert-manager or external-secrets updates the Kubernetes Secret, Kubernetes propagates the change to the mounted volume within the kubelet sync period (typically 60–90 seconds). New connections made after the next poll use the new certificate.

Agents do not need to be restarted when the server certificate rotates, as long as the new certificate is signed by a CA the agent already trusts. See Agent TLS configuration for how agents trust the server certificate.

Disabling TLS

Set the TLS values to false (or remove them) and redeploy:

trustDomainDeployment:
tls:
enabled: false
secretName: ""

Download the latest Trust Domain Server Helm Chart

You can download the latest version of the Helm chart by running the following command.

helm pull oci://ghcr.io/spirl/charts/spirl-server -d .

Deploy Trust Domain Servers

You can deploy Trust Domain Servers using the following command. The following constraints apply:

  1. The --namespace value must contain the trustDomainDeployment.id defined in values.yaml
  2. The helm RELEASE argument (first positional argument) must equal the trustDomainDeployment.id defined in values.yaml
helm upgrade --install --namespace $YOUR_TD_DEPLOYMENT_ID-example \
--create-namespace \
--values ./values.yaml \
$YOUR_TD_DEPLOYMENT_ID ./spirl-server-0.38.0.tgz

The command should produce output similar to the following:

Release "tdd-nnlo6k3t3o" does not exist. Installing it now.
NAME: tdd-nnlo6k3t3o
LAST DEPLOYED: Tue Dec 19 08:28:26 2023
NAMESPACE: tdd-nnlo6k3t3o-example
STATUS: deployed
REVISION: 1
TEST SUITE: None

Configuration Examples

HTTPS Proxy

If your cluster requires an HTTP proxy for outbound connections to the Defakto control plane, configure the proxy environment variables using trustDomainDeployment.deployment.env:

trustDomainDeployment:
deployment:
env:
HTTPS_PROXY: "http://proxy.company.com:8080"
NO_PROXY: ".cluster.local,.svc,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

Set NO_PROXY to exclude cluster-internal traffic from the proxy. At minimum, include your cluster's service and pod CIDR ranges.

Helm Values Reference

This section provides a comprehensive reference for all configuration options available in the Trust Domain Server Helm chart. These values can be used to customize your Trust Domain Server deployment to meet specific requirements.

Images Configuration

  • images.repository: Base repository for all images (default: "ghcr.io/spirl")
  • images.pullPolicy: Image pull policy (default: "IfNotPresent")
  • images.pullSecrets: Array of image pull secrets (default: [])
  • images.pullCredentials: Array of registries and corresponding secrets in the form base64("username:password"). The array will be used to generate a dockerconfigjson secret that will be used as an imagePullSecret (default: [])
  • images.trustDomainDeployment.name: Trust Domain Server image name (default: "spirl-server")
  • images.trustDomainDeployment.tag: Trust Domain Server image tag (default: Chart appVersion)
  • images.trustDomainDeployment.repository: Trust Domain Server-specific repository (optional)
  • images.firefly.name: Firefly integration image name (default: "firefly")
  • images.firefly.tag: Firefly image tag (default: "v1.9.1")
  • images.firefly.repository: Firefly-specific repository (default: "registry.venafi.cloud/public/venafi-images")

ArgoCD Configuration

  • argocd.enabled: Enable ArgoCD annotations for Kubernetes resources (default: false). When enabled, all Kubernetes resources will be annotated with ArgoCD-specific annotations that govern resource lifecycle management.

Trust Domain Deployment Configuration

Basic Configuration

  • trustDomainDeployment.trustDomainName: Name of the trust domain (e.g., "spirl.example.com")
  • trustDomainDeployment.trustDomainID: ID of the trust domain from registration (e.g., "td-diok4t8ahq")
  • trustDomainDeployment.id: Deployment ID generated during deployment creation (e.g., "tdd-nnlo6k3t3o")
  • trustDomainDeployment.name: Deployment name specified during creation (e.g., "us-west-2")
  • trustDomainDeployment.maxUnavailable: Maximum number of unavailable instances in pod disruption budget (default: 1)

Deployment Configuration

  • trustDomainDeployment.deployment.replicaCount: Number of replicas (default: 1)
  • trustDomainDeployment.deployment.env: Map of environment variables (default: {"SPIRL_ENV": "prod"})
  • trustDomainDeployment.deployment.additionalArgs: Array of additional command-line arguments (default: [])
  • trustDomainDeployment.deployment.additionalVolumes: Array of additional volumes (default: [])
  • trustDomainDeployment.deployment.additionalVolumeMounts: Array of additional volume mounts (default: [])
  • trustDomainDeployment.deployment.additionalContainers: Array of additional sidecar containers (default: [])
  • trustDomainDeployment.deployment.annotations: Map of pod annotations (default: {})
  • trustDomainDeployment.deployment.nodeSelector: Map of node selector labels (default: {})
  • trustDomainDeployment.deployment.additionalLabels: Map of additional pod labels (default: {})
  • trustDomainDeployment.deployment.resources: Resource requests and limits
  • trustDomainDeployment.deployment.affinity: Node affinity rules
  • trustDomainDeployment.deployment.topologySpreadConstraints: Array of topology spread constraints (default: [])
  • trustDomainDeployment.deployment.tolerations: Array of node tolerations (default: [])
  • trustDomainDeployment.deployment.drainDuration: Duration to leave listening servers up during shutdown to allow load balancer draining (default: "10s")
  • trustDomainDeployment.deployment.strategy: Deployment strategy configuration for rolling updates

Extension Configuration

  • trustDomainDeployment.deployment.extension.webhookUrl: Webhook URL for the extension service
  • trustDomainDeployment.deployment.extension.timeout: Timeout for extension calls (optional)
  • trustDomainDeployment.deployment.extension.invokeForClusterIds: Array of cluster IDs for which the extension should be invoked (default: [])
  • trustDomainDeployment.deployment.extension.webhookCaCert: CA certificate to validate the extension webhook's TLS certificate (optional)
  • trustDomainDeployment.deployment.extension.authenticationType: Authentication type for extension webhooks (values: NONE, BEARER)
  • trustDomainDeployment.deployment.extension.token: Token for BEARER authentication (default: "/var/run/secrets/kubernetes.io/serviceaccount/token")

Horizontal Pod Autoscaler Configuration

  • trustDomainDeployment.deployment.hpa.enabled: Enable horizontal pod autoscaling (default: false)
  • trustDomainDeployment.deployment.hpa.minReplicas: Minimum number of replicas (default: 1)
  • trustDomainDeployment.deployment.hpa.maxReplicas: Maximum number of replicas (default: 7)
  • trustDomainDeployment.deployment.hpa.targetCPUUtilizationPercentage: Target CPU utilization percentage (default: 50)
  • trustDomainDeployment.deployment.hpa.behavior: HPA behavior configuration

Jobs Configuration

  • trustDomainDeployment.jobs.annotations: Map of annotations for job pods (default: {})
  • trustDomainDeployment.initEncKeysJob.annotations: Map of annotations for encryption keys initialization job (default: {})
  • trustDomainDeployment.initJwtKeyJob.annotations: Map of annotations for JWT key initialization job (default: {})
  • trustDomainDeployment.rotateJwtKeyCronJob.annotations: Map of annotations for JWT key rotation CronJob (default: {})

Service Account Configuration

  • trustDomainDeployment.serviceAccount.create: Create service account (default: true)
  • trustDomainDeployment.serviceAccount.createRoles: Create roles for the service account (default: false)
  • trustDomainDeployment.serviceAccount.name: Service account name (auto-generated if not specified)
  • trustDomainDeployment.serviceAccount.annotations: Map of service account annotations (default: {})

Service Configuration

  • trustDomainDeployment.service.type: Kubernetes service type (default: "ClusterIP")
  • trustDomainDeployment.service.port: Service port number (default: 80)
  • trustDomainDeployment.service.annotations: Map of service annotations (default: {})

TLS Configuration

  • trustDomainDeployment.tls.enabled: Enable TLS termination on the agent API listener (:8180) (default: false). Requires health.enabled: true.
  • trustDomainDeployment.tls.secretName: Name of a Kubernetes Secret of type kubernetes.io/tls containing tls.crt and tls.key. Both enabled: true and a non-empty secretName are required for TLS to be configured.

Ingress Configuration

  • trustDomainDeployment.ingress.enabled: Enable ingress (default: false)
  • trustDomainDeployment.ingress.className: Ingress class name
  • trustDomainDeployment.ingress.hosts: Array of host configurations
    • trustDomainDeployment.ingress.hosts[].host: Host name
    • trustDomainDeployment.ingress.hosts[].paths: Array of path configurations
      • trustDomainDeployment.ingress.hosts[].paths[].path: URL path
      • trustDomainDeployment.ingress.hosts[].paths[].pathType: Path type (e.g., "Prefix")
  • trustDomainDeployment.ingress.tls: Array of TLS configurations
    • trustDomainDeployment.ingress.tls[].secretName: TLS secret name
    • trustDomainDeployment.ingress.tls[].hosts: Array of hosts for this TLS configuration
  • trustDomainDeployment.ingress.annotations: Map of ingress annotations (default: {})

Gateway Configuration (Istio)

  • trustDomainDeployment.gateway.enabled: Enable gateway (default: false)
  • trustDomainDeployment.gateway.certManager.enabled: Enable cert-manager integration (default: false)
  • trustDomainDeployment.gateway.certManager.email: Email for cert-manager
  • trustDomainDeployment.gateway.certManager.issuer: Certificate issuer
  • trustDomainDeployment.gateway.selector: Map of gateway selector labels (default: {})
  • trustDomainDeployment.gateway.tlsCredentialName: TLS credential name
  • trustDomainDeployment.gateway.host: Gateway host

Virtual Service Configuration (Istio)

  • trustDomainDeployment.virtualService.enabled: Enable virtual service (default: false)

Security Configuration

  • trustDomainDeployment.podSecurityContext: Pod security context configuration
  • trustDomainDeployment.containerSecurityContext: Container security context configuration

SVID Configuration

  • trustDomainDeployment.x509SVIDSubject: X.509 SVID subject configuration
  • trustDomainDeployment.x509SVIDTTL: X.509 SVID time-to-live (e.g., "1h")
  • trustDomainDeployment.jwtSVIDTTL: JWT SVID time-to-live (e.g., "5m")
  • trustDomainDeployment.allowedAttributes: Array of allowed workload attributes (default: [])

Session and Debug Configuration

  • trustDomainDeployment.sessionExpiration: Session expiration duration
  • trustDomainDeployment.pprof: Enable pprof profiling (default: false)

Federation Configuration

  • trustDomainDeployment.federation.oidcIssuer: OIDC issuer URL for federation
  • trustDomainDeployment.federation.trustBundleEndpointListenPort: Port for trust bundle endpoint (default: 0, disabled)

Debug Service Configuration

  • trustDomainDeployment.debugService.enabled: Enable debug service (default: false)

Control Plane Configuration

Authentication Configuration

  • controlPlane.auth.mode: Authentication mode (default: "direct"). Valid values:
    • direct - Connect directly to control plane (requires key)
    • agent - Use local Defakto Agent via Workload API
    • disabled - Disable authentication
  • controlPlane.auth.endpoint: Control plane authentication endpoint (default: "auth.cp.spirl.com:443")
  • controlPlane.auth.suppliedSecretName: Name of pre-existing secret for authentication (alternative to key)
  • controlPlane.auth.key.id: Trust domain key ID from registration
  • controlPlane.auth.key.pem: Private key for authentication (PEM format)

Events Configuration

  • controlPlane.events.endpoint: Events service endpoint (default: "events.cp.spirl.com:443")
  • controlPlane.events.serverName: Server name for TLS verification (optional, uses hostname from endpoint if not specified)

Relay Configuration

  • controlPlane.relay.endpoint: Relay service endpoint (default: "relay-web.cp.spirl.com:443")
  • controlPlane.relay.spiffeIDPrefix: SPIFFE ID prefix for relay validation (default: "spiffe://spirl.internal/us-west-2/spirl/relay")
  • controlPlane.relay.useWebPKI: Use Web PKI for relay connections (default: true)
  • controlPlane.relay.webPKISupplementalRootCAs: Supplemental root CAs for Web PKI (PEM format)
  • controlPlane.relay.serverName: Server name for TLS verification (optional, uses hostname from endpoint if not specified)

Cloud Provider Configuration

AWS Configuration

  • aws.kmsKeyARN: AWS KMS key ARN for encryption
  • aws.endpoints.kms: Custom KMS endpoint URL

Azure Configuration

  • azure.keyVault.url: Azure Key Vault URL
  • azure.keyVault.keyName: Key name in Key Vault
  • azure.keyVault.keyVersion: Key version (optional, defaults to latest)

GCP Configuration

  • gcp.projectID: GCP project ID
  • gcp.location: GCP location/region
  • gcp.kms.keyRing: KMS key ring name
  • gcp.kms.keyName: KMS key name

Integrations Configuration

Venafi Firefly Integration

  • integrations.venafi.firefly.suppliedSecretName: Name of pre-existing secret for Firefly authentication
  • integrations.venafi.firefly.config.clientID: Firefly client ID
  • integrations.venafi.firefly.config.policyName: Firefly policy name
  • integrations.venafi.firefly.config.trustAnchorPem: Trust anchor certificate (PEM format)
  • integrations.venafi.firefly.config.svcAccKeyPem: Service account key (PEM format)
  • integrations.venafi.firefly.resources: Resource requests and limits for Firefly sidecar

Telemetry Configuration

  • telemetry.enabled: Enable telemetry collection (default: true)
  • telemetry.metricsAPI.port: Port for metrics API exposure (default: 9090)
  • telemetry.collectors.grpc.emitLatencyMetrics: Enable gRPC latency metrics (default: true)
Latency Metrics

Latency monitoring metrics are enabled by default. Be aware that time histogram metrics for gRPC servers and clients can increase cardinality. See Prometheus best practices for more information on metric cardinality.

Health Configuration

  • health.enabled: Enable health server (default: true). Required when trustDomainDeployment.tls.enabled is true, since Kubernetes probes cannot use TLS. The chart fails at render time if TLS is on but the health server is off.
  • health.port: Port for health server (default: 8086)

Advanced Configuration

  • skipNameChecks: Skip name validation checks (default: false)
  • global: Free-form global configuration object for advanced use cases when embedding helm sub-charts.