From 2a01a9cc4fa8c7e3d7fb1636197a35a8400f5651 Mon Sep 17 00:00:00 2001 From: Lorenzo Boccaccia Date: Thu, 10 Sep 2026 15:30:47 +0200 Subject: [PATCH] feat(cloudformation): Add DevOps Agent alarm investigations template Forward a single CloudWatch alarm to a DevOps Agent generic webhook so the alarm opens an investigation. An EventBridge rule scoped to the alarm ARN matches ALARM state changes, an input transformer builds the incident payload, and an API destination POSTs it using an API key connection. No Lambda function is involved. Move devops-agent-skill-policies.yaml into its own directory and give it a README so each template is self-documenting, and update the links that referenced the old path. --- .claude/CLAUDE.md | 5 +- .kiro/steering/project-conventions.md | 5 +- README.md | 4 +- .../README.md | 80 ++++++ .../devops-agent-alarm-investigations.yaml | 234 ++++++++++++++++++ .../devops-agent-skill-policies/README.md | 119 +++++++++ .../devops-agent-skill-policies.yaml | 0 skills/aws-backup-coverage-review/README.md | 4 +- .../references/backup-best-practices.md | 2 +- .../README.md | 2 +- skills/ecs-operation-review/README.md | 2 +- skills/msk-operations/README.md | 2 +- 12 files changed, 447 insertions(+), 12 deletions(-) create mode 100644 cloudformation/devops-agent-alarm-investigations/README.md create mode 100644 cloudformation/devops-agent-alarm-investigations/devops-agent-alarm-investigations.yaml create mode 100644 cloudformation/devops-agent-skill-policies/README.md rename cloudformation/{ => devops-agent-skill-policies}/devops-agent-skill-policies.yaml (100%) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index b2b09993..a4c0c381 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -20,7 +20,8 @@ tools-for-devops-agent/ ├── llms.txt # Structured repo overview for AI tools ├── .gitignore # Root-level ignores ├── cloudformation/ -│ └── devops-agent-skill-policies.yaml # IAM policies skills require +│ ├── devops-agent-skill-policies/ # IAM policies skills require +│ └── devops-agent-alarm-investigations/ # CloudWatch alarm → DevOps Agent webhook ├── docs/ # GitHub Pages (mkdocs) documentation site ├── skills/ │ ├── .gitignore # Allowlist for DevOps Agent supported extensions only @@ -200,7 +201,7 @@ Only these extensions are permitted inside **skill** directories (enforced by `s 6. Test the skill with DevOps Agent before submitting. 7. Update the root `README.md` skills table with the new skill's name, agent types, author, and docs link. 8. Update the `llms.txt` file at the repo root — add the new skill to the "Available Skills" section following the existing format: `- [Skill Name](skills//SKILL.md): One-line description`. -9. If the skill requires IAM permissions beyond the `AIDevOpsAgentAccessPolicy` managed policy, add a new parameter, condition, and inline policy resource to `cloudformation/devops-agent-skill-policies.yaml`, and update the `SkillPolicySummary` output. +9. If the skill requires IAM permissions beyond the `AIDevOpsAgentAccessPolicy` managed policy, add a new parameter, condition, and inline policy resource to `cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml`, and update the `SkillPolicySummary` output. ## Zipping for Upload diff --git a/.kiro/steering/project-conventions.md b/.kiro/steering/project-conventions.md index 443d1ece..143a5d45 100644 --- a/.kiro/steering/project-conventions.md +++ b/.kiro/steering/project-conventions.md @@ -20,7 +20,8 @@ tools-for-devops-agent/ ├── llms.txt # Structured repo overview for AI tools ├── .gitignore # Root-level ignores ├── cloudformation/ -│ └── devops-agent-skill-policies.yaml # IAM policies skills require +│ ├── devops-agent-skill-policies/ # IAM policies skills require +│ └── devops-agent-alarm-investigations/ # CloudWatch alarm → DevOps Agent webhook ├── docs/ # GitHub Pages (mkdocs) documentation site ├── skills/ │ ├── .gitignore # Allowlist for DevOps Agent supported extensions only @@ -199,7 +200,7 @@ Only these extensions are permitted inside **skill** directories (enforced by `s 6. Test the skill with DevOps Agent before submitting. 7. Update the root `README.md` skills table with the new skill's name, description, agent types, author, and docs link. 8. Update the `llms.txt` file at the repo root — add the new skill to the "Available Skills" section following the existing format: `- [Skill Name](skills//SKILL.md): One-line description`. -9. If the skill requires IAM permissions beyond the `AIDevOpsAgentAccessPolicy` managed policy, add a new parameter, condition, and inline policy resource to `cloudformation/devops-agent-skill-policies.yaml`, and update the `SkillPolicySummary` output. +9. If the skill requires IAM permissions beyond the `AIDevOpsAgentAccessPolicy` managed policy, add a new parameter, condition, and inline policy resource to `cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml`, and update the `SkillPolicySummary` output. ## Maintaining llms.txt diff --git a/README.md b/README.md index c85743ba..2284811a 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,13 @@ Most permissions are already covered by the AWS managed policy [`AIDevOpsAgentAc ```bash aws cloudformation deploy \ - --template-file cloudformation/devops-agent-skill-policies.yaml \ + --template-file cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml \ --stack-name devops-agent-skill-policies \ --parameter-overrides ExistingRoleName= \ --capabilities CAPABILITY_NAMED_IAM ``` -The template supports enabling/disabling policies per skill, optional region restrictions, and can either attach to an existing role or create a new one. See [`cloudformation/devops-agent-skill-policies.yaml`](cloudformation/devops-agent-skill-policies.yaml) for details. +The template supports enabling/disabling policies per skill, optional region restrictions, and can either attach to an existing role or create a new one. See [`cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml`](cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml) for details. ## Contributing diff --git a/cloudformation/devops-agent-alarm-investigations/README.md b/cloudformation/devops-agent-alarm-investigations/README.md new file mode 100644 index 00000000..9223ed2a --- /dev/null +++ b/cloudformation/devops-agent-alarm-investigations/README.md @@ -0,0 +1,80 @@ +# DevOps Agent alarm investigations + +Forwards **one** Amazon CloudWatch alarm to an AWS DevOps Agent generic webhook, so the +alarm opens an investigation. **One stack = one alarm** — deploy it again per alarm. + +No Lambda and no code: an Amazon EventBridge rule scoped to the alarm ARN matches +`CloudWatch Alarm State Change` with `state.value = ALARM`, an input transformer builds +the incident payload, and an EventBridge API destination POSTs it. The API key lives in an +EventBridge connection, which sends it as `Authorization: Bearer `. An IAM role grants +the rule `events:InvokeApiDestination` on that one destination. + +The payload carries only the alarm ARN and the raised state — no alarm name, reason, or +metric data. DevOps Agent enriches from the ARN. + +## Before you deploy + +The webhook is created in the console (there is no `CreateWebhook` API) and its API key is +shown only once, so it must exist first: + +1. Create the Agent Space. +2. Console → **Capabilities → Agent Space Webhook → Generate webhook**, authentication type + **API key**. Copy the URL and the key — the key is not retrievable later. +3. Deploy this stack with that URL, that key, and the alarm ARN. + +Lost the key? Rotate the webhook from the Capabilities tab; rotation keeps the URL and +issues a new key. Update the stack afterwards — the connection re-reads the key only when +the stack is updated. + +## Parameters + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `WebhookUrl` | *(required)* | HTTPS URL of the generic webhook. | +| `WebhookApiKey` | *(required)* | The API key from webhook creation. `NoEcho`, so it is masked in stack events and `describe-stacks`. | +| `AlarmArn` | *(required)* | ARN of the single alarm to forward. | +| `InvocationRateLimitPerSecond` | `300` | Cap on webhook invocations per second — 300 is the per-destination quota, so the stack adds no throttling. Lower it only to deliberately rate-limit the webhook. | +| `DevOpsAgentAlarmIntegrationTag` | *(stack name)* | Value of the `DevOpsAgent` tag on the rule and role. Identification and cost allocation only; does not affect routing. | + +## Deploy + +```bash +aws cloudformation deploy \ + --template-file cloudformation/devops-agent-alarm-investigations/devops-agent-alarm-investigations.yaml \ + --stack-name devops-agent-alarm-investigations- \ + --capabilities CAPABILITY_IAM \ + --parameter-overrides \ + WebhookUrl="https://" \ + WebhookApiKey="" \ + AlarmArn="arn:aws:cloudwatch:::alarm:" +``` + +## Notes + +- **Cross-Region and cross-account alarms.** Deploy this stack once, in the DevOps Agent's + account and Region, and set `AlarmArn` to the alarm's real (possibly remote) ARN. Remote + alarms reach it via ordinary + [bus-to-bus forwarding](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cross-account.html): + a rule in the alarm's own Region/account targeting the agent Region's default bus, plus — + cross-account only — a resource policy on the agent bus allowing `PutEvents` from the + source account. The forwarded event still carries the alarm ARN in `resources`, so this + stack's rule matches it. +- **Region availability.** API destinations to public HTTPS endpoints are not available in + every Region — check + [API destinations as targets](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-destinations.html#eb-api-destination-regions). +- **Deduplication.** `incidentId` is the EventBridge event id, constant across retries, so + redeliveries reuse it instead of opening duplicates. Control flapping at the alarm's + datapoints-to-alarm setting. +- **Delivery.** Up to 32 retry attempts over 8 hours; API destinations require a response + within 5 seconds. `MaximumEventAgeInSeconds` stops retries once an event is older than + the window, so a late redelivery cannot open a stale investigation. +- **Monitoring.** There is no log group. The rule publishes `InvocationAttempts`, + `SuccessfulInvocationAttempts`, `RetryInvocationAttempts` and `FailedInvocations` in + `AWS/Events` by `RuleName`. Alarm on `FailedInvocations`; add a dead-letter queue to the + target to inspect events that never landed. +- **Keeping the key in your own secret.** Replace `ApiKeyValue` with + `'{{resolve:secretsmanager:MyWebhookSecret}}'` and drop the `WebhookApiKey` parameter, so + the key never passes through a stack parameter. Same rotation caveat as above. +- **API key versus HMAC.** The webhook also supports HMAC, but EventBridge connections + support only Basic, API key, and OAuth and cannot sign per request — HMAC would need a + signing Lambda in between. This template takes the API key path to stay code-free. diff --git a/cloudformation/devops-agent-alarm-investigations/devops-agent-alarm-investigations.yaml b/cloudformation/devops-agent-alarm-investigations/devops-agent-alarm-investigations.yaml new file mode 100644 index 00000000..80b53322 --- /dev/null +++ b/cloudformation/devops-agent-alarm-investigations/devops-agent-alarm-investigations.yaml @@ -0,0 +1,234 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: > + Forwards a single Amazon CloudWatch alarm to an AWS DevOps Agent webhook so that + alarm opens an investigation. One stack = one alarm: it creates an Amazon + EventBridge rule scoped to that alarm's ARN, an EventBridge connection holding the + webhook API key, an EventBridge API destination pointing at the webhook, and a role + that lets the rule invoke it. No AWS Lambda function is involved. + + Prerequisite: create the Agent Space and its generic webhook with API key + authentication first (console — no API), then pass the webhook URL, the API key, + and the alarm ARN to this stack. + +Metadata: + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: AWS DevOps Agent Webhook + Parameters: + - WebhookUrl + - WebhookApiKey + - Label: + default: Alarm + Parameters: + - AlarmArn + - Label: + default: Delivery Tuning (optional) + Parameters: + - InvocationRateLimitPerSecond + - DevOpsAgentAlarmIntegrationTag + ParameterLabels: + WebhookUrl: + default: DevOps Agent generic (API key) webhook URL + WebhookApiKey: + default: Webhook API key (bearer token) + AlarmArn: + default: ARN of the single CloudWatch alarm to forward + InvocationRateLimitPerSecond: + default: Max webhook invocations per second + DevOpsAgentAlarmIntegrationTag: + default: Value for the DevOpsAgent tag (optional; defaults to the stack name) + +Parameters: + WebhookUrl: + Type: String + Description: > + HTTPS URL of the AWS DevOps Agent generic webhook, created in the Agent Space + console with API key authentication. + AllowedPattern: '^https://[A-Za-z0-9.-]+(:[0-9]+)?(/.*)?$' + ConstraintDescription: Must be an HTTPS URL. + + WebhookApiKey: + Type: String + NoEcho: true + Description: > + The API key (bearer token) shown once when you created the webhook. It is stored + in an AWS Secrets Manager secret that EventBridge creates and owns for the + connection. To keep the key in a secret you own instead, see the README. + MinLength: 1 + ConstraintDescription: Must not be empty. + + AlarmArn: + Type: String + Description: > + ARN of the single Amazon CloudWatch alarm this stack forwards. Only ALARM + state changes for this exact alarm are sent to the webhook. + AllowedPattern: '^arn:aws[a-zA-Z-]*:cloudwatch:[a-z0-9-]+:[0-9]{12}:alarm:.+' + ConstraintDescription: Must be a CloudWatch alarm ARN. + + DevOpsAgentAlarmIntegrationTag: + Type: String + Default: '' + Description: > + (Optional) Value applied as the DevOpsAgent tag on the resources this stack + creates (identification / cost allocation only; does not affect routing, which + is determined by the webhook URL). Defaults to the stack name when left empty. + MaxLength: 256 + AllowedPattern: "^[A-Za-z0-9 _.:/=+@-]{0,256}$" + ConstraintDescription: > + Up to 256 characters using letters, numbers, spaces, and _ . : / = + - @ + (the AWS tag-value character set), or empty to use the stack name. + + InvocationRateLimitPerSecond: + Type: Number + Default: 300 + MinValue: 1 + MaxValue: 300 + Description: > + (Optional) Maximum webhook invocations per second for the API destination. The + default of 300 is the per-destination quota, so this stack adds no throttling of + its own: one alarm cannot approach that rate, while a low cap would queue + concurrent events (a flapping alarm overlapping a retry) and delay them. Lower it + only to deliberately rate-limit the webhook. + ConstraintDescription: > + Between 1 and 300. 300 is the default 'Rate of invocations per API destination' + quota; lower this value to throttle, and raise the quota first if you need more. + +Conditions: + # An empty tag value falls back to the stack name. A parameter Default cannot + # itself be an intrinsic, so the fallback is resolved here instead. + HasTagValue: !Not [!Equals [!Ref DevOpsAgentAlarmIntegrationTag, '']] + +Resources: + # Holds the bearer token. EventBridge stores it in a Secrets Manager secret it + # creates and owns for this connection, and adds the header on every invocation. + WebhookConnection: + Type: AWS::Events::Connection + Properties: + Description: !Sub 'API key for the AWS DevOps Agent webhook (${AWS::StackName}).' + AuthorizationType: API_KEY + AuthParameters: + ApiKeyAuthParameters: + # The DevOps Agent webhook expects the token as a bearer token, so the + # header name is Authorization and the value carries the Bearer prefix. + ApiKeyName: Authorization + ApiKeyValue: !Sub 'Bearer ${WebhookApiKey}' + + WebhookApiDestination: + Type: AWS::Events::ApiDestination + Properties: + Description: !Sub 'AWS DevOps Agent webhook (${AWS::StackName}).' + ConnectionArn: !GetAtt WebhookConnection.Arn + InvocationEndpoint: !Ref WebhookUrl + HttpMethod: POST + InvocationRateLimitPerSecond: !Ref InvocationRateLimitPerSecond + + # An API destination target requires a role granting events:InvokeApiDestination. + InvokeWebhookRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: events.amazonaws.com + Action: sts:AssumeRole + Condition: + StringEquals: + aws:SourceAccount: !Ref 'AWS::AccountId' + Policies: + - PolicyName: invoke-devops-agent-webhook + PolicyDocument: + Version: '2012-10-17' + Statement: + - Sid: InvokeWebhookApiDestination + Effect: Allow + Action: events:InvokeApiDestination + Resource: !GetAtt WebhookApiDestination.Arn + Tags: + - Key: ManagedBy + Value: CloudFormation + - Key: DevOpsAgent + Value: !If + - HasTagValue + - !Ref DevOpsAgentAlarmIntegrationTag + - !Ref 'AWS::StackName' + + # Rule scoped to exactly one alarm ARN — the rule itself is the filter, so no + # code is needed to decide whether an event should be forwarded. + AlarmStateChangeRule: + Type: AWS::Events::Rule + Properties: + Description: !Sub 'Forwards ALARM-state changes for ${AlarmArn} to the DevOps Agent webhook.' + EventPattern: + source: + - aws.cloudwatch + detail-type: + - CloudWatch Alarm State Change + resources: + - !Ref AlarmArn + detail: + state: + value: + - ALARM + State: ENABLED + Targets: + - Id: DevOpsAgentWebhook + Arn: !GetAtt WebhookApiDestination.Arn + RoleArn: !GetAtt InvokeWebhookRole.Arn + HttpParameters: + HeaderParameters: + Content-Type: application/json + # incidentId is the EventBridge event id, which is constant across + # retries, so DevOps Agent deduplicates redeliveries of the same event + # instead of opening a new investigation for each attempt. + InputTransformer: + InputPathsMap: + eventId: $.id + eventTime: $.time + alarmArn: $.resources[0] + InputTemplate: | + { + "eventType": "incident", + "incidentId": "", + "action": "created", + "priority": "HIGH", + "title": "CloudWatch alarm in ALARM state", + "description": "CloudWatch alarm entered ALARM state.", + "timestamp": "", + "data": { + "metadata": { + "alarmArn": "", + "state": "ALARM" + } + } + } + RetryPolicy: + MaximumRetryAttempts: 32 + MaximumEventAgeInSeconds: 28800 + Tags: + - Key: ManagedBy + Value: CloudFormation + - Key: DevOpsAgent + Value: !If + - HasTagValue + - !Ref DevOpsAgentAlarmIntegrationTag + - !Ref 'AWS::StackName' + +Outputs: + ApiDestinationArn: + Description: ARN of the API destination that posts to the webhook. + Value: !GetAtt WebhookApiDestination.Arn + + ConnectionArn: + Description: ARN of the EventBridge connection holding the webhook API key. + Value: !GetAtt WebhookConnection.Arn + + EventRuleArn: + Description: ARN of the EventBridge rule scoped to the alarm. + Value: !GetAtt AlarmStateChangeRule.Arn + + ForwardedAlarmArn: + Description: The CloudWatch alarm this stack forwards. + Value: !Ref AlarmArn diff --git a/cloudformation/devops-agent-skill-policies/README.md b/cloudformation/devops-agent-skill-policies/README.md new file mode 100644 index 00000000..12d90985 --- /dev/null +++ b/cloudformation/devops-agent-skill-policies/README.md @@ -0,0 +1,119 @@ +# DevOps Agent skill IAM policies + +Adds the extra IAM permissions individual skills need to a DevOps Agent role, on top +of the AWS managed policy +[`AIDevOpsAgentAccessPolicy`](https://docs.aws.amazon.com/devopsagent/latest/userguide/aws-devops-agent-security-devops-agent-iam-permissions.html). + +Attach the policies to a role you already have, or let the template create one. This +template creates **no** infrastructure — only IAM. + +> This template does **not** create an Agent Space. Deploy the space separately and +> associate the role ARN from this stack's `DevOpsAgentRoleArn` output. + +## Role: existing or new + +| `ExistingRoleName` | Behaviour | +|--------------------|-----------| +| set to a role name | Attaches the inline policies to that existing role. | +| left empty (default) | Creates `DevOpsAgentRole-AgentSpace`, trusting `aidevops.amazonaws.com`, with `AIDevOpsAgentAccessPolicy` attached. | + +The trust policy on the created role is scoped with `aws:SourceAccount` and +`aws:SourceArn` (`arn:aws:aidevops:*::agentspace/*`) for confused-deputy +prevention. + +> **Multiple Agent Spaces:** the created role trusts all Agent Spaces in the account +> (`agentspace/*`), so one role can serve several spaces. Because the new-role name is +> fixed, the create-new path can only run once per account/Region. To give different +> spaces different permission sets, pre-create the roles and deploy this stack once per +> role with `ExistingRoleName`. + +## Parameters + +### Role configuration + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `ExistingRoleName` | `''` | Attach policies to this existing role. Empty creates `DevOpsAgentRole-AgentSpace`. | + +### Skill activation + +Each parameter is `'true'` / `'false'` and defaults to `'true'`. Set a skill to +`'false'` to leave out its policy. + +| Parameter | Skill | Permissions added | +|-----------|-------|-------------------| +| `EnableAwsHealthEvents` | `aws-health-events` | `health:DescribeEventTypes` | +| `EnableSupportCases` | `support-cases` | `support:DescribeCommunications` | +| `EnableRdsOperationReview` | `rds-operation-review` | `rds:DownloadDBLogFilePortion`, `logs:GetLogEvents` | +| `EnableInvestigationCostGuardrail` | `investigation-cost-guardrail` | `pricing:GetProducts` | +| `EnableMskOperations` | `msk-operations` | `kafka:GetBootstrapBrokers` | +| `EnableServiceQuotaCheck` | `service-quota-check` | Service Quotas read + `RequestServiceQuotaIncrease`, `CreateSupportCase`; `cloudwatch:GetMetricData`, `cloudwatch:GetMetricStatistics` | +| `EnableDmsOperationReview` | `database-migration-service-expertise` | `dms:TestConnection` | +| `EnableEcsOperationReview` | `ecs-operation-review` | `compute-optimizer:GetECSServiceRecommendations` | +| `EnableAwsBackupCoverageReview` | `aws-backup-coverage-review` | `backup:GetSupportedResourceTypes`, `config:SelectResourceConfig`, `dsql:ListClusters`, `storagegateway:ListFileShares`, `storagegateway:ListGateways`, `storagegateway:ListVolumes` | +| `EnableAgentCoreObservabilitySetup` | `agentcore-observability-setup` | `bedrock-agentcore:GetAgentRuntime`, `bedrock-agentcore:ListAgentRuntimes`, `xray:GetTraceSegmentDestination`, `logs:DescribeDeliveries`, `logs:DescribeDeliverySources`, `logs:DescribeDeliveryDestinations`, `logs:DescribeResourcePolicies`, `lambda:GetFunctionConfiguration`, `ecs:DescribeTaskDefinition`, `ecs:DescribeServices`, `ecs:ListTasks`, `eks:DescribeCluster` | +| `EnableAgentCoreOpsReview` | `agentcore-ops-review` | `bedrock-agentcore` read-only List/Get for runtimes, memories, gateways, browsers, code interpreters and workload identities; `bedrock-agentcore:ListMemoryRecords`; `ec2:DescribeSubnets` | +| `EnableEksOperationReview` | `aws-eks-operations-review` | None — already covered by the managed policy | +| `EnableEnrichWithSecurityAgent` | `enrich-with-aws-security-agent` | None — already covered by the managed policy | +| `EnableCrmInvestigationGuidelines` | `crm-production-investigation-guidelines` | None — already covered by the managed policy | +| `EnableSkipScheduledMaintenance` | `skip-scheduled-maintenance` | None — no IAM required | + +The last four parameters exist so the skill list stays complete and self-documenting; +toggling them changes nothing in the stack. + +`EnableAwsHealthEvents` and `EnableSupportCases` need an AWS Business or Enterprise +Support plan for the underlying APIs to return data. + +### Optional resource scoping + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `AllowedRegions` | `''` | Comma-delimited Region list. Empty means all Regions. When set, adds a `Deny` on every action outside those Regions, excepting the global services `health`, `support`, and `ce`. | + +## Always applied + +One policy is added regardless of the skill toggles: + +| Policy | Purpose | +|--------|---------| +| `AllowCreateResourceExplorerSLR` | `iam:CreateServiceLinkedRole` for `AWSServiceRoleForResourceExplorer`, required for topology discovery. | + +## Deploy + +Attach to an existing role: + +```bash +aws cloudformation deploy \ + --template-file cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml \ + --stack-name devops-agent-skill-policies \ + --parameter-overrides ExistingRoleName= \ + --capabilities CAPABILITY_NAMED_IAM +``` + +Create a new role instead, restricted to two Regions and without the Support-plan +skills: + +```bash +aws cloudformation deploy \ + --template-file cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml \ + --stack-name devops-agent-skill-policies \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameter-overrides \ + AllowedRegions="us-east-1,eu-west-1" \ + EnableAwsHealthEvents=false \ + EnableSupportCases=false +``` + +## Outputs + +| Output | Description | +|--------|-------------| +| `DevOpsAgentRoleArn` | Role ARN to associate with your Agent Space. | +| `DevOpsAgentRoleName` | Role name. | +| `SkillPolicySummary` | Which skills got an inline policy, which are covered by the managed policy, and which need no IAM. | + +## Adding a skill + +When a new skill needs permissions beyond the managed policy, add a parameter, a +condition, and an `AWS::IAM::Policy` resource following the existing pattern, then +extend the `SkillPolicySummary` output. diff --git a/cloudformation/devops-agent-skill-policies.yaml b/cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml similarity index 100% rename from cloudformation/devops-agent-skill-policies.yaml rename to cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml diff --git a/skills/aws-backup-coverage-review/README.md b/skills/aws-backup-coverage-review/README.md index c800b250..5b2c9bcb 100644 --- a/skills/aws-backup-coverage-review/README.md +++ b/skills/aws-backup-coverage-review/README.md @@ -69,13 +69,13 @@ storagegateway:ListVolumes `sts:GetCallerIdentity` is also used and requires no IAM permission. Deploy them with the `EnableAwsBackupCoverageReview` parameter in -[cloudformation/devops-agent-skill-policies.yaml](https://github.com/aws/tools-for-devops-agent/blob/main/cloudformation/devops-agent-skill-policies.yaml). +[cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml](https://github.com/aws/tools-for-devops-agent/blob/main/cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml). **Each Agent Space has its own IAM role, so apply this to the role of every space where the skill is installed** — use one stack per role: ```bash aws cloudformation deploy \ - --template-file cloudformation/devops-agent-skill-policies.yaml \ + --template-file cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml \ --stack-name devops-agent-skill-policies- \ --parameter-overrides ExistingRoleName= \ EnableAwsBackupCoverageReview=true \ diff --git a/skills/aws-backup-coverage-review/references/backup-best-practices.md b/skills/aws-backup-coverage-review/references/backup-best-practices.md index d1601e9f..6ba88ec7 100644 --- a/skills/aws-backup-coverage-review/references/backup-best-practices.md +++ b/skills/aws-backup-coverage-review/references/backup-best-practices.md @@ -110,7 +110,7 @@ Use these in the Recommendation column, matched by check ID. The review is read-only. The baseline `AIDevOpsAgentAccessPolicy` covers most control-plane reads; the AWS-managed `AWSBackupAuditAccess` policy is the closest managed equivalent for the AWS Backup portion. See the skill README for the exact -action list and `cloudformation/devops-agent-skill-policies.yaml` for the +action list and `cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml` for the deployable policy. ## Canonical AWS documentation URLs diff --git a/skills/database-migration-service-expertise/README.md b/skills/database-migration-service-expertise/README.md index eb920c5f..fb8d0c52 100644 --- a/skills/database-migration-service-expertise/README.md +++ b/skills/database-migration-service-expertise/README.md @@ -31,7 +31,7 @@ You need an existing [Agent Space](https://docs.aws.amazon.com/devopsagent/lates ### 2. IAM permissions for DMS read access -The Agent Space IAM role needs read-only permissions for DMS resources. Nearly all required actions are already covered by the `AIDevOpsAgentAccessPolicy` managed policy attached to the DevOps Agent role. The one exception is `dms:TestConnection`, which must be granted separately — use the [CloudFormation template](https://github.com/aws/tools-for-devops-agent/blob/main/cloudformation/devops-agent-skill-policies.yaml). +The Agent Space IAM role needs read-only permissions for DMS resources. Nearly all required actions are already covered by the `AIDevOpsAgentAccessPolicy` managed policy attached to the DevOps Agent role. The one exception is `dms:TestConnection`, which must be granted separately — use the [CloudFormation template](https://github.com/aws/tools-for-devops-agent/blob/main/cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml). For reference, the complete action set used by this skill: ```json diff --git a/skills/ecs-operation-review/README.md b/skills/ecs-operation-review/README.md index 1b57f7c6..98b4576e 100644 --- a/skills/ecs-operation-review/README.md +++ b/skills/ecs-operation-review/README.md @@ -43,7 +43,7 @@ An existing [Agent Space](https://docs.aws.amazon.com/devopsagent/latest/usergui ### 2. Read-only permissions -The Agent Space IAM role needs read-only (`describe*` / `list*` / `get*`) access to: ECS, CloudWatch, CloudWatch Logs, IAM, Application Auto Scaling, Elastic Load Balancing v2, ECR, EC2/VPC, GuardDuty, and Compute Optimizer. The DevOps Agent managed policy **`AIDevOpsAgentAccessPolicy`** covers all of these except one: it grants no `compute-optimizer` actions, so the PERF8 rightsizing check needs `compute-optimizer:GetECSServiceRecommendations` added. Deploy `cloudformation/devops-agent-skill-policies.yaml` with `EnableEcsOperationReview=true` to attach it as a gated inline policy. Without it the skill still runs — PERF8 is marked N/A under the access-limitation protocol. No cluster-level access entry or kubectl connectivity is required — ECS is assessed entirely through AWS control-plane APIs. +The Agent Space IAM role needs read-only (`describe*` / `list*` / `get*`) access to: ECS, CloudWatch, CloudWatch Logs, IAM, Application Auto Scaling, Elastic Load Balancing v2, ECR, EC2/VPC, GuardDuty, and Compute Optimizer. The DevOps Agent managed policy **`AIDevOpsAgentAccessPolicy`** covers all of these except one: it grants no `compute-optimizer` actions, so the PERF8 rightsizing check needs `compute-optimizer:GetECSServiceRecommendations` added. Deploy `cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml` with `EnableEcsOperationReview=true` to attach it as a gated inline policy. Without it the skill still runs — PERF8 is marked N/A under the access-limitation protocol. No cluster-level access entry or kubectl connectivity is required — ECS is assessed entirely through AWS control-plane APIs. ### 3. AWS Knowledge MCP diff --git a/skills/msk-operations/README.md b/skills/msk-operations/README.md index cf4686dd..a9ff1b48 100644 --- a/skills/msk-operations/README.md +++ b/skills/msk-operations/README.md @@ -49,7 +49,7 @@ The AWS DevOps Agent's primary cloud-source role needs read access to MSK and CloudWatch. All calls except `kafka:GetBootstrapBrokers` are covered by `AIDevOpsAgentAccessPolicy`. `kafka:GetBootstrapBrokers` is granted by the opt-in `EnableMskOperations` parameter (default `true`) in -[`cloudformation/devops-agent-skill-policies.yaml`](https://github.com/aws/tools-for-devops-agent/blob/main/cloudformation/devops-agent-skill-policies.yaml). +[`cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml`](https://github.com/aws/tools-for-devops-agent/blob/main/cloudformation/devops-agent-skill-policies/devops-agent-skill-policies.yaml). The full set of actions the skill uses in practice: ```