---
title: "Infrastructure"
description: "Zero secrets in config. Zero secrets in logs. Docker, Kubernetes, Terraform, Ansible, CI/CD, and everything else."
lang: en
url: https://clavitor.ai/en/developers/infrastructure
markdown: https://clavitor.ai/en/developers/infrastructure.md
authoritative: true
translations: [de, fr, es, it, pt, nl, pl, sv, da, no, fi, uk, ru, tr, ja, ko, zh, hi, th, vi, id]
publisher: Clavitor LLC
---

# Infrastructure: Zero secrets in config. Zero secrets in logs.

Every platform, every orchestrator, every CI runner. The proxy works with anything that makes HTTP calls. The CLI works with anything that can shell out. If your system is older than your career, it still works.

## The proxy is the universal integration.

If your workload makes HTTPS calls, the Clavitor proxy injects credentials at the network layer. No code changes. No SDKs. No secrets in environment variables, config files, or logs. Set `HTTPS_PROXY` and your existing code works unchanged — the proxy resolves `clavitor://` references in request headers before the request leaves the machine.

```
$ export HTTPS_PROXY=http://localhost:1983
$ curl -H "Authorization: Bearer clavitor://Stripe API/key" \
  https://api.stripe.com/v1/charges
# The agent never sees sk_live_... — only clavitor:// appears in logs

```

## Containers: Docker and Kubernetes

### Docker Compose

Run the Clavitor proxy on the host and point your containers at it. Credentials are injected transparently into outbound requests — no secrets in environment variables, no secrets baked into images.

```
# On the Docker host

$ clavitor-proxy serve &
```

```
# docker-compose.yml — containers route through the host-mode proxy

services:
  app:
    environment:
      - HTTPS_PROXY=http://host.docker.internal:1983
    extra_hosts:
      - "host.docker.internal:host-gateway"
```

Or use `render` to resolve a config template at startup:

```
$ clavitor-cli render app.config.template.yml | docker compose -f - up
```

### Kubernetes

Create secrets from the vault without hardcoding values in manifests:

```
$ kubectl create secret generic app-secrets \
  --from-literal=db-pass="$(clavitor-cli get 'Production DB' --field password)" \
  --from-literal=api-key="$(clavitor-cli get 'Stripe API' --field key)"
```

For runtime credential injection, deploy the proxy as a sidecar container in your pod. Application containers set `HTTPS_PROXY` to the sidecar. Credentials are resolved per-request, never stored in etcd.

## IaC: Terraform, Ansible, Pulumi

### Terraform

Resolve credentials into the provider environment before `terraform apply`. The AWS provider reads its credentials from standard environment variables — Clavitor populates them inline, the .tf file mentions no secret.

```
$ export AWS_ACCESS_KEY_ID=$(clavitor-cli get "AWS Root" --field access_key_id)
$ export AWS_SECRET_ACCESS_KEY=$(clavitor-cli get "AWS Root" --field secret_key)
$ terraform apply
```

The `provider "aws" {}` block stays empty in your code. Same pattern works for any Terraform provider that supports env-var credentials (which is most of them).

### Ansible

```
- name: Get database password
  command: clavitor-cli get "Production DB" --field password
  register: db_pass
  no_log: true

- name: Configure app
  template:
    src: app.conf.j2
  vars:
    db_password: "{{ db_pass.stdout }}"
```

### Pulumi

```
import { execSync } from 'child_process';
const dbPass = execSync('clavitor-cli get "Production DB" --field password').toString().trim();
new aws.rds.Instance("db", { masterPassword: new pulumi.secret(dbPass) });
```

## CI/CD: GitHub Actions, GitLab CI, Jenkins

The token is piped on stdin in every example below — keeping it out of `argv` so it does not appear in `/proc/<pid>/cmdline` or build logs.

### GitHub Actions

```
- name: Deploy
  env:
    CLAVITOR_TOKEN: ${{ secrets.CLAVITOR_TOKEN }}
  run: |
    echo "$CLAVITOR_TOKEN" | clavitor-cli init
    kubectl create secret generic app-secrets \
      --from-literal=api-key="$(clavitor-cli get 'Deploy Token' --field key)" \
      --dry-run=client -o yaml | kubectl apply -f -
```

### GitLab CI

```
deploy:
  script:
    - echo "$CLAVITOR_TOKEN" | clavitor-cli init
    - clavitor-cli get "Deploy Key" --field private_key | ssh-add -
    - ssh deploy@production "systemctl restart app"
```

### Jenkins

```
pipeline {
  stages {
    stage('Deploy') {
      steps {
        sh 'echo "$CLAVITOR_TOKEN" | clavitor-cli init'
        sh 'clavitor-cli get "Deploy Key" --field private_key | ssh-add -'
        sh 'ssh deploy@production "systemctl restart app"'
      }
    }
  }
}
```

## SSH: Vault-stored keys

```
$ clavitor-cli get "Deploy Key" --field private_key | ssh-add -
$ ssh deploy@production
```

The private key is piped directly into `ssh-add`. It never touches disk, never appears in shell history, and is cleared from the agent when the session ends.

## Legacy systems: If it makes an HTTP call, it works.

The proxy doesn't care what language made the request. COBOL, FORTRAN, Perl, Visual Basic, a 30-year-old batch job — if the process makes an HTTPS request, the proxy intercepts it, resolves the `clavitor://` reference, and injects the real credential. No code changes required.

For systems that can't make HTTP calls, use `clavitor-cli render` to resolve a config template before the process starts. The template is safe to store anywhere. The resolved output goes to stdin or a temporary file with restricted permissions.

```
# Resolve credentials before the batch job starts

$ clavitor-cli render db-connect.template.cfg > /tmp/db-connect.cfg
$ chmod 600 /tmp/db-connect.cfg
$ /opt/legacy/batch-job --config /tmp/db-connect.cfg
$ rm /tmp/db-connect.cfg
```

## The pattern is always the same.

CLI for scripts and pipelines. Proxy for HTTP workloads. Render for config files. Every secret resolved at runtime, never stored.
[Start free](https://clavitor.ai/en/checkout)
[Developer overview →](https://clavitor.ai/en/developers)
