AWS Lambda deployment template for epithet SSH certificate authority and policy server.
Use this template to deploy your own epithet CA and policy servers on AWS Lambda with API Gateway, Secrets Manager, SSM Parameter Store, and S3 certificate archival.
Clone or fork this repository to create your own deployment:
git clone https://github.com/epithet-ssh/epithet-aws.git my-ssh-ca
cd my-ssh-caMake this a private repo as you will have things like your OIDC info in the config file.
Edit config/policy/policy.yaml to configure your OIDC provider and authorization rules:
# CA public key is loaded from SSM Parameter Store at runtime
# This placeholder satisfies config validation
ca_public_key: "placeholder - loaded from SSM"
oidc:
issuer: https://accounts.google.com
audience: your-oauth-client-id.apps.googleusercontent.com
users:
admin@example.com: [wheel, admin]
dev@example.com: [dev]
defaults:
allow:
root: [wheel]
expiration: "5m"
hosts:
"prod-*":
allow:
root: [admin]
expiration: "2m"See config/policy/policy.example.yaml for a comprehensive example with all OIDC providers and the epithet policy documentation for detailed configuration options.
# Optional: customize region and project name in terraform/terraform.tfvars
# aws_region = "us-east-1"
# project_name = "my-ssh-ca"
# Deploy infrastructure
make init
make applyAfter the infrastructure is deployed, generate and upload your CA key pair:
make setup-ca-keyThis creates an Ed25519 key pair and stores:
- Private key in AWS Secrets Manager
- Public key in SSM Parameter Store
# Get the CA URL for epithet client configuration
tofu -chdir=terraform output ca_url
# Get the CA public key (for sshd TrustedUserCAKeys)
aws ssm get-parameter \
--name $(tofu -chdir=terraform output -raw ca_public_key_parameter) \
--query Parameter.Value --output text \
--region $(tofu -chdir=terraform output -raw region)On your SSH servers, add the CA public key to trust certificates:
# Add to /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca_key.pub
# Save the CA public key
echo "ssh-ed25519 AAAA..." > /etc/ssh/ca_key.pub
# Reload sshd
service sshd reload # or: systemctl reload sshdepithet-aws/
├── cmd/epithet-aws/ # Lambda handler binary
│ ├── main.go # CLI entry point
│ └── aws.go # CA and policy Lambda handlers
├── config/
│ └── policy/ # Policy configuration (bundled in Lambda)
│ └── policy.yaml
├── pkg/s3archiver/ # S3 certificate archival package
├── terraform/ # OpenTofu/Terraform deployment
│ ├── main.tf # Provider and common config
│ ├── ca.tf # CA Lambda, API Gateway, S3
│ ├── policy.tf # Policy Lambda, API Gateway
│ ├── secrets.tf # Secrets Manager, SSM Parameter
│ ├── variables.tf # Input variables
│ └── outputs.tf # Output values
└── scripts/ # Deployment automation
| Command | Description |
|---|---|
make build |
Build local binary for testing |
make build-lambda |
Build Lambda deployment packages |
make test |
Run Go tests |
make init |
Initialize Terraform |
make plan |
Build Lambda and run Terraform plan |
make apply |
Build and deploy to AWS |
make setup-ca-key |
Generate and upload CA key pair |
make destroy |
Tear down all AWS resources |
Client (epithet agent)
↓
API Gateway (HTTPS)
↓
CA Lambda ←→ Policy Lambda
↓ ↓
Secrets Mgr SSM Param
(private key) (public key)
↓
S3 (cert archive)
- Signs SSH certificates based on policy server decisions
- Loads CA private key from AWS Secrets Manager
- Archives certificates to S3
Environment variables (set by Terraform):
CA_SECRET_ARN: Secrets Manager ARN for CA private keyPOLICY_URL: Internal URL of policy LambdaCERT_ARCHIVE_BUCKET: S3 bucket for archivalCERT_ARCHIVE_PREFIX: S3 key prefix (default: "certs")EPITHET_CMD: Set to "ca"
- Validates OIDC tokens from users
- Evaluates authorization rules from bundled config
- Loads CA public key from SSM Parameter Store
- Returns certificate parameters
Environment variables (set by Terraform):
CA_PUBLIC_KEY_PARAM: SSM parameter name for CA public keyEPITHET_CMD: Set to "policy"
Edit config/policy/policy.yaml and redeploy:
vim config/policy/policy.yaml
make applyThe policy file is bundled into the Lambda zip, so redeployment is required for changes to take effect.
With typical personal use (a few connections per day):
| Service | Monthly Cost |
|---|---|
| API Gateway | ~$0.05 |
| Lambda | ~$0.10 |
| Secrets Manager | ~$0.40 |
| S3 | ~$0.01 |
| SSM Parameter | Free |
| Total | < $1 |
This template is designed to be forked and customized.
Create terraform/terraform.tfvars:
aws_region = "us-east-1"
project_name = "my-ssh-ca"
lambda_memory_mb = 256
log_retention_days = 30go get github.com/epithet-ssh/epithet@v0.2.0
go mod tidy
make apply# CA Lambda
aws logs tail /aws/lambda/$(tofu -chdir=terraform output -raw project_name)-ca \
--since 10m --region $(tofu -chdir=terraform output -raw region)
# Policy Lambda
aws logs tail /aws/lambda/$(tofu -chdir=terraform output -raw project_name)-policy \
--since 10m --region $(tofu -chdir=terraform output -raw region)- "CA public key not set": Run
make setup-ca-keyafter initial deployment - "ca_public_key is required": Ensure policy.yaml has the placeholder
ca_public_keyfield - 500 errors: Check Lambda logs for detailed error messages
Same as epithet - see LICENSE in main repository.
- epithet - Core SSH CA implementation