Security & Trust

Agents join the team. They do not take the keys.

How it works is the experience. This page is the boundary: GitHub scopes, who assumes AWS or Azure, the three IAM documents and their Azure RBAC equivalents (only CloudFormation / ARM is the live role), what licensed agents can and cannot do, and how humans stay in the loop.

Exact GitHub permissions

Connect GitHub with OAuth. Day-to-day work is the repository you pick — not every org, not billing, not admin.

repo

Read and write the selected delivery repository: files, branches, commits, and pull requests.

read:user

Read the signed-in GitHub user so VPods can list repositories you can attach.

AWS read-only model

Compliance and posture agents scan. They do not provision. Scans use a dedicated read-only role: IAM MFA, S3 encryption, security groups, CloudTrail, and markdown evidence — not Create* on the delivery stack.

Delivery still lands in your account or subscription. Mira writes Terraform. Frank writes Actions. Your CI assumes VPodsDeploy with OIDC (AWS) or an Entra federated credential (Azure) and apply. VPods never assumes that role or identity. Saving the connection only checks format — we do not probe sts:AssumeRole or Azure ARM from our control plane.

Three IAM documents (AWS)

Only C is attached when you launch the CloudFormation stack. A and B are extra JSON in the wizard — they are not the live role. C has API Gateway, Lambda, SQS, and IAM role create. C does not include AppSync; B does. Agents never receive a long-lived access key in chat.

C — CloudFormation VPodsDeploy (what customers launch)

Live stack policy. Inline policy on the role GitHub Actions assume. Includes API Gateway, Lambda, SQS, IAM role create, and cloudfront:*. Does not include AppSync.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AmplifyHostedApp",
      "Effect": "Allow",
      "Action": [
        "amplify:StartJob",
        "amplify:GetApp",
        "amplify:GetBranch",
        "amplify:ListJobs"
      ],
      "Resource": "*"
    },
    {
      "Sid": "StaticHosting",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket",
        "cloudfront:CreateInvalidation"
      ],
      "Resource": "*"
    },
    {
      "Sid": "TerraformApply",
      "Effect": "Allow",
      "Action": [
        "cloudformation:*",
        "iam:PassRole",
        "iam:GetRole",
        "iam:CreateRole",
        "iam:DeleteRole",
        "iam:AttachRolePolicy",
        "iam:DetachRolePolicy",
        "iam:PutRolePolicy",
        "iam:DeleteRolePolicy",
        "lambda:*",
        "apigateway:*",
        "dynamodb:*",
        "amplify:*",
        "s3:*",
        "cloudfront:*",
        "logs:*",
        "events:*",
        "sns:*",
        "sqs:*",
        "ecs:*",
        "ecr:*",
        "sts:GetCallerIdentity"
      ],
      "Resource": "*"
    }
  ]
}

A — Deploy IAM JSON (wizard copy)

Not what the stack attaches. Not attached by the stack. Amplify host plus named CreateDistribution / CreateBucket.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AmplifyCloudFrontHost",
      "Effect": "Allow",
      "Action": [
        "amplify:CreateApp",
        "amplify:CreateBranch",
        "amplify:StartJob",
        "amplify:GetApp",
        "amplify:GetBranch",
        "amplify:ListJobs",
        "amplify:UpdateApp",
        "cloudfront:CreateDistribution",
        "cloudfront:UpdateDistribution",
        "cloudfront:CreateInvalidation",
        "cloudfront:GetDistribution",
        "s3:CreateBucket",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket",
        "s3:PutBucketPolicy",
        "s3:GetBucketLocation"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ReadOwnIdentity",
      "Effect": "Allow",
      "Action": [
        "sts:GetCallerIdentity"
      ],
      "Resource": "*"
    }
  ]
}

B — Terraform IAM JSON (wizard copy)

Not what the stack attaches. Not attached by the stack. Wider than C — includes AppSync, RDS, Route 53, KMS. Do not describe C as having AppSync.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "TerraformApplyCore",
      "Effect": "Allow",
      "Action": [
        "cloudformation:*",
        "iam:PassRole",
        "iam:GetRole",
        "iam:CreateRole",
        "iam:DeleteRole",
        "iam:AttachRolePolicy",
        "iam:DetachRolePolicy",
        "iam:PutRolePolicy",
        "iam:DeleteRolePolicy",
        "iam:CreatePolicy",
        "iam:GetPolicy",
        "iam:TagRole",
        "lambda:*",
        "apigateway:*",
        "appsync:*",
        "dynamodb:*",
        "s3:*",
        "cloudfront:*",
        "amplify:*",
        "logs:*",
        "events:*",
        "sns:*",
        "sqs:*",
        "ecs:*",
        "ecr:*",
        "elasticloadbalancing:*",
        "ec2:Describe*",
        "ec2:CreateTags",
        "rds:*",
        "route53:*",
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:GenerateDataKey",
        "kms:DescribeKey",
        "kms:CreateGrant",
        "secretsmanager:GetSecretValue",
        "secretsmanager:CreateSecret",
        "secretsmanager:PutSecretValue",
        "ssm:GetParameter",
        "ssm:PutParameter",
        "sts:GetCallerIdentity"
      ],
      "Resource": "*"
    }
  ]
}

Three RBAC documents (Azure)

Same A / B / C split. Only C is attached when you launch the ARM template: a user-assigned identity with an Entra federated credential (GitHub or Azure DevOps) and a custom role. C has Functions, API Management, Service Bus / Event Grid, storage, Front Door, and role assignment. C does not include Azure SQL, Cosmos DB, Azure DNS, or Key Vault; B does. No client secret is exchanged.

C — ARM / Bicep VPodsDeploy (what customers launch)

Live template role. Custom role on the user-assigned identity GitHub Actions or Azure DevOps federate into. Includes Functions, APIM, Service Bus, Event Grid, storage, Front Door, and role assignment. Does not include Azure SQL, Cosmos DB, Azure DNS, or Key Vault.

{
  "Name": "VPodsDeployLeastPrivilege",
  "IsCustom": true,
  "Description": "C — attached to the launched identity. Functions, APIM, Service Bus / Event Grid, storage, Front Door, Static Web Apps, Container Apps / ACR, resource deployments, role assignment. Does not include Azure SQL, Cosmos DB, Azure DNS, or Key Vault.",
  "Actions": [
    "Microsoft.Web/staticSites/read",
    "Microsoft.Web/staticSites/listSecrets/action",
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write",
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete",
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read",
    "Microsoft.Cdn/profiles/afdendpoints/purge/action",
    "Microsoft.Cdn/profiles/endpoints/purge/action",
    "Microsoft.Resources/deployments/*",
    "Microsoft.Resources/subscriptions/resourceGroups/read",
    "Microsoft.Resources/subscriptions/resourceGroups/write",
    "Microsoft.Authorization/roleAssignments/read",
    "Microsoft.Authorization/roleAssignments/write",
    "Microsoft.Authorization/roleAssignments/delete",
    "Microsoft.Authorization/roleDefinitions/read",
    "Microsoft.Web/sites/*",
    "Microsoft.Web/staticSites/*",
    "Microsoft.ApiManagement/*",
    "Microsoft.Storage/*",
    "Microsoft.Cdn/*",
    "Microsoft.Network/frontDoors/*",
    "Microsoft.Insights/*",
    "Microsoft.OperationalInsights/workspaces/*",
    "Microsoft.EventGrid/*",
    "Microsoft.ServiceBus/*",
    "Microsoft.App/containerApps/*",
    "Microsoft.ContainerRegistry/*",
    "Microsoft.ManagedIdentity/userAssignedIdentities/read",
    "Microsoft.ManagedIdentity/userAssignedIdentities/assign/action"
  ],
  "NotActions": [],
  "DataActions": [],
  "AssignableScopes": [
    "/subscriptions/{subscriptionId}"
  ]
}

A — Deploy RBAC JSON (wizard copy)

Not what the template attaches. Not attached by the template. Static Web Apps / App Service plus named Front Door / CDN and storage create.

{
  "Name": "VPodsDeployStaticHost",
  "IsCustom": true,
  "Description": "A — wizard copy. Static Web Apps / App Service create plus Front Door / CDN and storage. Not attached by the ARM template.",
  "Actions": [
    "Microsoft.Web/staticSites/read",
    "Microsoft.Web/staticSites/write",
    "Microsoft.Web/staticSites/delete",
    "Microsoft.Web/sites/read",
    "Microsoft.Web/sites/write",
    "Microsoft.Cdn/profiles/read",
    "Microsoft.Cdn/profiles/write",
    "Microsoft.Cdn/profiles/endpoints/write",
    "Microsoft.Cdn/profiles/afdendpoints/write",
    "Microsoft.Cdn/profiles/afdendpoints/purge/action",
    "Microsoft.Network/frontDoors/read",
    "Microsoft.Network/frontDoors/write",
    "Microsoft.Storage/storageAccounts/read",
    "Microsoft.Storage/storageAccounts/write",
    "Microsoft.Storage/storageAccounts/blobServices/containers/write",
    "Microsoft.ManagedIdentity/userAssignedIdentities/read"
  ],
  "NotActions": [],
  "DataActions": [],
  "AssignableScopes": [
    "/subscriptions/{subscriptionId}"
  ]
}

B — Terraform RBAC JSON (wizard copy)

Not what the template attaches. Not attached by the template. Wider than C — includes Azure SQL, Cosmos DB, Azure DNS, Key Vault, and custom role definition write.

{
  "Name": "VPodsTerraformApply",
  "IsCustom": true,
  "Description": "B — wizard copy. Wider than C — includes Azure SQL, Cosmos DB, Azure DNS, Key Vault, and custom role definition write. Not attached by the ARM template.",
  "Actions": [
    "Microsoft.Resources/deployments/*",
    "Microsoft.Resources/subscriptions/resourceGroups/*",
    "Microsoft.Authorization/roleAssignments/*",
    "Microsoft.Authorization/roleDefinitions/*",
    "Microsoft.Web/sites/*",
    "Microsoft.Web/staticSites/*",
    "Microsoft.ApiManagement/*",
    "Microsoft.ServiceBus/*",
    "Microsoft.EventGrid/*",
    "Microsoft.Sql/*",
    "Microsoft.DocumentDB/*",
    "Microsoft.Network/dnszones/*",
    "Microsoft.KeyVault/*",
    "Microsoft.Storage/*",
    "Microsoft.Cdn/*",
    "Microsoft.Network/frontDoors/*",
    "Microsoft.App/containerApps/*",
    "Microsoft.ContainerRegistry/*",
    "Microsoft.Insights/*",
    "Microsoft.OperationalInsights/*",
    "Microsoft.ManagedIdentity/userAssignedIdentities/*"
  ],
  "NotActions": [],
  "DataActions": [],
  "AssignableScopes": [
    "/subscriptions/{subscriptionId}"
  ]
}

What agents can and cannot do

Can

  • Write code, Terraform, tests, and GitHub Actions in the connected repo through a controlled tool layer.
  • Open and update pull requests in the repository you selected.
  • Run on-demand AWS posture scans on a read-only scan role (Diane, Kai, and the compliance seats).
  • Diane and Kai persist scan output as markdown under compliance/ and security/ — not app, infra, or workflows.
  • Propose pipeline changes. Your CI still runs in your AWS account or Azure subscription.

Cannot

  • Call AWS, Azure, GitHub, or Jira with raw credentials from the agent prompt.
  • Apply Terraform from the VPods control plane. For every hire, apply is customer GitHub Actions or Azure DevOps with federated credentials. There is no second apply-capable agent system.
  • Assume VPodsDeploy from VPods. Agents never hold that AWS role or Azure identity.
  • Use root keys, org-admin GitHub, or unrestricted IAM / Owner RBAC.
  • Skip human approval on merge, pipeline promotion, or compliance decisions.
  • Run without an active paid subscription. Canceled or unpaid seats have zero access.

Data handling

GitHub remains the source of truth for code. Customer AWS or Azure remains the execution environment. Inference runs through the VPods control plane; deploys do not. VPods Inc. is a Canadian company. Canadian law governs the terms.

Human approval boundaries

People review code, approve pull requests, approve pipelines, and make compliance decisions. Agents can draft the change. They cannot terraform apply. Promotion stays in your GitHub environments.

Audit trail

Build logs, agent activity, infrastructure changes, and approvals stay attached to the story. You can see who did what, and when.

Compliance

The VPods team has 15 years in security and compliance (QSA, SOC 2, ISO 27001, PCI DSS). Licensed compliance agents produce evidence packs. They never claim your environment is certified.

See the experience next

Boundaries live here. The 60–90 second operating model lives on How it works.