Terraform Module
Provisions the least-privilege cross-account IAM role required to connect an AWS account to Vigilare. Idempotent — safe to run multiple times.
github.com/algofyczech/sentinel//terraform-modules/sentinel-onboarding>= 1.5>= 5.0Overview
What this module creates and how it fits into the Vigilare onboarding flow.
The sentinel-onboarding module creates a single IAM role in your AWS account. Vigilare assumes this role via sts:AssumeRole to collect billing, IAM, GuardDuty, SES, CloudTrail, service quota, and account-metadata signals — all read-only.
The trust policy is locked to the Vigilare platform AWS account ID and enforces an ExternalId condition (your unique token issued at registration) to prevent confused-deputy attacks.
Onboarding flow
- Sign up on the Vigilare dashboard and connect an AWS account.
- The dashboard returns your
external_idandsentinel_account_id. - Run this module with those values to create the IAM role.
- Copy the
role_arnoutput into the dashboard to complete verification. - Vigilare assumes the role and triggers the first scan immediately.
Requirements
Versions and providers this module depends on.
| Name | Version |
|---|---|
| terraform | >= 1.5 |
| hashicorp/aws | >= 5.0 |
Usage
Minimal configuration to provision the cross-account role.
module "sentinel_onboarding" {
source = "github.com/algofyczech/sentinel//terraform-modules/sentinel-onboarding"
# Issued by Vigilare during account registration — treat as a secret
external_id = var.sentinel_external_id
# The Vigilare platform AWS account (provided by Vigilare)
sentinel_account_id = "123456789012"
# Optional: customise the role name
role_name = "sentinel-readonly"
# Set to true if you have Business or Enterprise support
enable_support_tier = false
tags = {
Environment = "production"
CostCenter = "security"
}
}
# Pass the role ARN back to the Vigilare registration flow
output "sentinel_role_arn" {
value = module.sentinel_onboarding.role_arn
}external_id in a secret manager (AWS Secrets Manager, Terraform Cloud variables, or a .tfvars file excluded from source control). Do not commit it to your repository.Inputs
Variables accepted by the module. * marks required inputs.
| Name | Type | Default | Description |
|---|---|---|---|
| external_id* | string | required | External ID issued by Vigilare during account registration. Must be at least 32 characters. Used as a confused-deputy guard on sts:AssumeRole. |
| sentinel_account_id* | string | required | AWS account ID of the Vigilare platform (12 digits). Only this account may assume the role. |
| role_name | string | "sentinel-readonly" | Name of the IAM role to create. Changing this after initial deployment forces role re-creation. |
| enable_support_tier | bool | false | Set to true on Business or Enterprise support accounts to enable support:Describe* permissions used by the quota and account collectors. |
| tags | map(string) | {} | Additional tags to apply to the IAM role. The ManagedBy = "sentinel" tag is always added automatically. |
Outputs
Values exported after a successful apply.
| Name | Description |
|---|---|
| role_arn | Full ARN of the created IAM role. Paste this into the Vigilare dashboard to complete account registration. |
| role_name | Name of the created IAM role. |
Permissions granted
Complete list of IAM actions added to the inline policy. All actions are read-only. No write, delete, or mutating actions are included.
ce:GetCostAndUsagece:GetAnomaliesce:GetAnomalySubscriptionsce:GetAnomalyMonitorsce:ListCostAllocationTagsScope: Resource: *
budgets:DescribeBudgetsbudgets:DescribeBudgetPerformanceHistorybudgets:ViewBudgetScope: Resource: *
iam:GetAccountSummaryiam:GenerateCredentialReportiam:GetCredentialReportiam:ListUsersiam:ListVirtualMFADevicesiam:ListMFADevicesiam:ListAttachedUserPoliciesiam:ListUserPoliciesiam:GetUserPolicyiam:ListGroupsForUseriam:ListAttachedGroupPoliciesScope: Account-level actions on *, user/group actions scoped to account ARNs
access-analyzer:ListAnalyzersaccess-analyzer:ListFindingsaccess-analyzer:GetFindingScope: ListAnalyzers on *, findings scoped to analyzer ARNs in account
guardduty:ListDetectorsguardduty:GetDetectorguardduty:ListFindingsguardduty:GetFindingsguardduty:GetFindingsStatisticsScope: ListDetectors on *, detector actions scoped to detector ARNs in account
ses:GetSendStatisticsses:GetSendQuotasesv2:GetAccountsesv2:ListEmailIdentitiessesv2:GetEmailIdentityScope: Account actions on *, identity reads scoped to identity ARNs
cloudtrail:LookupEventscloudtrail:DescribeTrailscloudtrail:ListTrailscloudtrail:GetTrailStatusScope: List/lookup on *, GetTrailStatus scoped to trail ARNs in account
servicequotas:ListServiceQuotasservicequotas:GetServiceQuotaservicequotas:ListRequestedServiceQuotaChangescloudwatch:GetMetricDatacloudwatch:GetMetricStatisticscloudwatch:ListMetricsScope: Resource: *
account:GetContactInformationaccount:GetAlternateContactorganizations:DescribeOrganizationorganizations:DescribeAccountinvoicing:ListInvoiceSummariesScope: Resource: *
support:DescribeTrustedAdvisorCheckssupport:DescribeTrustedAdvisorCheckResultsupport:DescribeCasesScope: Resource: *
Security notes
Design decisions that limit the blast radius of the granted access.
Least privilege
All permissions are read-only (Get*, List*, Describe*, Lookup*). No write, delete, or mutating actions are granted.
Confused-deputy protection
The trust policy requires a matching sts:ExternalId condition. The external_id value is unique per connected account and must be treated as a secret.
No data exfiltration surface
The policy grants no s3:GetObject, no secretsmanager:GetSecretValue, no kms:Decrypt, and no ec2:GetConsoleOutput. It cannot read application data.
Resource-level scoping where possible
IAM user/group actions, Access Analyzer findings, GuardDuty detector operations, SES identity reads, and CloudTrail trail reads are all scoped to ARNs within the customer account. Actions that AWS does not support resource-level restrictions for remain on Resource: *.
Support permissions are opt-in
support:Describe* is only added when enable_support_tier = true, because these APIs require Business or Enterprise support and will fail with an authorization error on Developer/Basic plans.
Idempotency
The inline policy is managed entirely by Terraform and is reconciled on every apply. Manual changes in the console will be overwritten. Running apply multiple times with the same inputs produces no changes.
Questions about the module?
Our team can help with custom role names, multi-account setups, and enterprise deployment patterns.
Contact support