Cloud Credentials#
Each cloud provider requires an API token or service principal with specific permissions. InfraGuard reads credentials from environment variables, never from config files or IaC state.
DigitalOcean#
Set DIGITALOCEAN_TOKEN (used by both the Terraform provider and the Pulumi provider).
Required API Scopes#
The token needs read + write access. DigitalOcean personal access tokens are either read-only or read+write; there is no per-resource granularity. A read+write token covers all the resources InfraGuard creates.
Resources Created#
| Resource | Terraform | Pulumi |
|---|---|---|
digitalocean_tag | Yes | Yes |
digitalocean_firewall | Yes | Yes |
digitalocean_droplet | Yes | Yes |
digitalocean_ssh_key | No (key must already exist on account) | Yes (created automatically) |
With Terraform, the SSH key must be pre-registered on your DO account. The CLI computes the fingerprint from your public key file and passes it as a tfvar. Register the key with:
doctl compute ssh-key import infraguard --public-key-file ~/.ssh/id_ed25519.pubWith Pulumi, the SSH key resource is created automatically from the public key you provide. No pre-registration step is needed.
Minimum Permissions Summary#
- Droplets: create, read, delete
- Firewalls: create, read, delete
- Tags: create, read, delete
- SSH Keys: read (Terraform), or create, read, delete (Pulumi)
AWS#
Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (or use an AWS profile via AWS_PROFILE).
Minimum IAM Policy#
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:DescribeInstances",
"ec2:DescribeImages",
"ec2:CreateTags",
"ec2:DeleteTags",
"ec2:CreateSecurityGroup",
"ec2:DeleteSecurityGroup",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:AuthorizeSecurityGroupEgress",
"ec2:RevokeSecurityGroupIngress",
"ec2:RevokeSecurityGroupEgress",
"ec2:DescribeSecurityGroups",
"ec2:ImportKeyPair",
"ec2:DeleteKeyPair",
"ec2:DescribeKeyPairs"
],
"Resource": "*"
}
]
}Resources Created#
| Resource | Notes |
|---|---|
aws_key_pair | Created from your SSH public key |
aws_security_group | HTTP/HTTPS open, SSH restricted to operator IP |
aws_instance | EC2 instance with Ubuntu 22.04 AMI |
Azure#
Authenticate via service principal. Set ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID, and ARM_SUBSCRIPTION_ID.
Minimum Role#
The service principal needs the Contributor role on the target subscription or resource group. A custom role with narrower permissions:
{
"Name": "InfraGuard Deployer",
"Actions": [
"Microsoft.Resources/subscriptions/resourceGroups/write",
"Microsoft.Resources/subscriptions/resourceGroups/delete",
"Microsoft.Resources/subscriptions/resourceGroups/read",
"Microsoft.Network/virtualNetworks/*",
"Microsoft.Network/networkSecurityGroups/*",
"Microsoft.Network/publicIPAddresses/*",
"Microsoft.Network/networkInterfaces/*",
"Microsoft.Compute/virtualMachines/*"
],
"AssignableScopes": ["/subscriptions/<your-subscription-id>"]
}Resources Created#
| Resource | Notes |
|---|---|
azurerm_resource_group | Contains all other resources |
azurerm_virtual_network | 10.0.0.0/16 address space |
azurerm_subnet | 10.0.1.0/24 |
azurerm_public_ip | Static Standard SKU |
azurerm_network_security_group | HTTP/HTTPS open, SSH restricted, deny-all fallback |
azurerm_network_interface | Bound to subnet and public IP |
azurerm_linux_virtual_machine | Ubuntu 22.04 LTS Gen2, SSH user operator |
Hetzner#
Set HCLOUD_TOKEN (used by both the Terraform hcloud provider and the Pulumi hcloud provider).
Required Permissions#
Hetzner API tokens are scoped to a project. A Read & Write token on the target project is required.
Resources Created#
| Resource | Notes |
|---|---|
hcloud_ssh_key | Created from your SSH public key |
hcloud_firewall | HTTP/HTTPS open, SSH restricted to operator IP |
hcloud_server | Ubuntu 22.04, firewall attached at creation |
Cloudflare (Terraform only)#
Set CLOUDFLARE_API_TOKEN.
Cloudflare is Terraform-only. It deploys a Workers relay, not a VPS. There is no SSH, no health check, and no bootstrap step.
Required Token Permissions#
| Permission | Access |
|---|---|
| Zone / Workers Routes | Edit |
| Zone / Zone | Read |
| Account / Workers Scripts | Edit |
Scope the token to the specific zone (domain) you are deploying to.
Resources Created#
| Resource | Notes |
|---|---|
cloudflare_workers_script | Transparent HTTP relay to your backend |
cloudflare_workers_route | Binds the script to your domain pattern |
Security Notes#
- Credentials are passed as environment variables, never stored in Terraform state or Pulumi config.
- Cloud-init scripts do not embed API tokens. Secrets are deployed post-provision via SSH/SCP.
- Terraform state is age-encrypted after apply and the plaintext is deleted (when
--state-keyis provided). - Pulumi uses a local file backend with no passphrase. State stays on your machine.