From 9239bc0c888ff1b7b0089a6a7bab377025846e35 Mon Sep 17 00:00:00 2001 From: Lorenzo Boccaccia Date: Mon, 3 Aug 2026 11:35:20 +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. One stack per alarm: an EventBridge rule scoped to the alarm ARN, an input transformer that builds the incident payload, an API destination and connection that POST it with the webhook API key, and a role limited to invoking that destination. No Lambda function and no code. incidentId is the EventBridge event id, which is constant across retries, so redeliveries deduplicate instead of opening a second investigation. The retry policy caps delivery at 32 attempts over eight hours and stops retrying events older than that. Give each template its own directory named after the template file, holding the template and a README.md, and add a README for the existing skill-policies template. Update the references to the skill-policies template path that the move would otherwise break, and correct the repository name in the two contributor-facing convention docs. --- .claude/CLAUDE.md | 4 +- .kiro/steering/project-conventions.md | 4 +- README.md | 4 +- .../README.md | 165 +++++++++++++ .../devops-agent-alarm-investigations.yaml | 220 ++++++++++++++++++ .../devops-agent-skill-policies/README.md | 115 +++++++++ .../devops-agent-skill-policies.yaml | 0 .../README.md | 2 +- skills/msk-operations/README.md | 2 +- 9 files changed, 508 insertions(+), 8 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 ba5393d..45a3c51 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -11,7 +11,7 @@ This repository consolidates AWS DevOps Agent skills. Follow these conventions w ## Repository Structure ``` -sample-devops-agent-tools/ +tools-for-devops-agent/ ├── README.md # Project overview with skills table ├── .gitignore # Root-level ignores ├── skills/ @@ -126,7 +126,7 @@ Only these extensions are permitted inside skill directories (enforced by `skill 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 ebf7373..c88b8ea 100644 --- a/.kiro/steering/project-conventions.md +++ b/.kiro/steering/project-conventions.md @@ -11,7 +11,7 @@ This repository consolidates AWS DevOps Agent skills. Follow these conventions w ## Repository Structure ``` -sample-devops-agent-tools/ +tools-for-devops-agent/ ├── README.md # Project overview with skills table ├── .gitignore # Root-level ignores ├── skills/ @@ -125,7 +125,7 @@ Only these extensions are permitted inside skill directories (enforced by `skill 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 ef66d82..6c60f31 100644 --- a/README.md +++ b/README.md @@ -43,13 +43,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 0000000..9daaa5a --- /dev/null +++ b/cloudformation/devops-agent-alarm-investigations/README.md @@ -0,0 +1,165 @@ +# DevOps Agent alarm investigations + +Forwards **one** Amazon CloudWatch alarm to an AWS DevOps Agent generic webhook so that +alarm opens an investigation. + +**One stack = one alarm.** Deploy it again for each alarm you want forwarded. + +There is no AWS Lambda function and no code: an Amazon EventBridge rule matches the +alarm, an input transformer builds the webhook payload, and an EventBridge API +destination posts it with the webhook's API key. + +## Deployment sequence + +The webhook is created manually in the console (there is no `CreateWebhook` API), and +its API key is shown only once at creation — so it must exist **before** this stack. + +``` +1. Create the Agent Space (console / CLI / CloudFormation). +2. Console → Capabilities → Agent Space Webhook → Generate webhook. ← manual; no API + For "Webhook authentication type" choose API key. + Copy the webhook URL and the API key. The key is not retrievable later. +3. Deploy this stack with the webhook URL, the API key, and the alarm ARN. + Deploy once per alarm. +``` + +If you lose the key, rotate the webhook from the Capabilities tab. Rotation keeps the +same URL and issues a new key; update this stack with the new value afterwards. + +## What it creates + +| Resource | Purpose | +|----------|---------| +| Amazon EventBridge rule | Matches `CloudWatch Alarm State Change` events with `state.value = ALARM` **for the one configured alarm ARN** — the rule itself is the filter. Its input transformer builds the incident payload. | +| Amazon EventBridge connection | Holds the API key. EventBridge stores it in a Secrets Manager secret it creates and owns, and adds `Authorization: Bearer ` to every request. | +| Amazon EventBridge API destination | The webhook endpoint, invoked at a capped rate. | +| AWS IAM role | Lets the rule invoke that one API destination (`events:InvokeApiDestination`). Nothing else. | + +## How it works + +``` +CloudWatch alarm ──ALARM──▶ EventBridge rule (this alarm ARN only) + │ input transformer builds the incident JSON + ▼ + API destination + connection + │ POST, Authorization: Bearer + ▼ + DevOps Agent generic webhook ──▶ investigation +``` + +The payload the transformer produces: + +```json +{ + "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" } } +} +``` + +Only the alarm ARN and the raised state are forwarded — no alarm name, reason, or metric +data. DevOps Agent enriches from the ARN. + +## Parameters + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `WebhookUrl` | *(required)* | HTTPS URL of the generic webhook. | +| `WebhookApiKey` | *(required)* | The API key (bearer token) from webhook creation. `NoEcho`, so it is masked in stack events, the console, and `describe-stacks`. | +| `AgentName` | *(required)* | Name/label of the target DevOps Agent. Used only to tag the taggable resources (`DevOpsAgent=`) for identification and cost allocation; it does not affect routing. | +| `AlarmArn` | *(required)* | ARN of the single CloudWatch alarm to forward. | +| `InvocationRateLimitPerSecond` | `1` | Cap on webhook invocations per second. Raise only if one stack must absorb a burst. | + +## 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="" \ + AgentName="" \ + AlarmArn="arn:aws:cloudwatch:::alarm:" +``` + +## Cross-region and cross-account alarms + +Deploy this stack **once, in the same account and Region as the DevOps Agent**. Alarms in +*other* Regions or accounts reach it by **forwarding their state-change events** to the +agent Region's event bus; the rule matches on the alarm ARN, so a forwarded remote event +is handled exactly like a local one. Set `AlarmArn` to the alarm's real (possibly remote) +ARN. + +You create the forwarding rule in the alarm's own Region/account — ordinary EventBridge +bus-to-bus delivery: + +1. In the **alarm's Region/account**, create an EventBridge rule on the default bus + matching the alarm, targeting the **agent account/Region's default event bus**, with + an IAM role that grants `events:PutEvents` to that bus: + ```yaml + ForwardToAgentBus: + Type: AWS::Events::Rule + Properties: + EventPattern: + source: [aws.cloudwatch] + detail-type: [CloudWatch Alarm State Change] + detail: { state: { value: [ALARM] } } + Targets: + - Id: AgentBus + Arn: arn:aws:events:::event-bus/default + RoleArn: !GetAtt ForwardRole.Arn # role with events:PutEvents on that bus + ``` +2. **Cross-account only:** also add a resource policy on the agent bus + (`events:PutPermission`) allowing the source account to `PutEvents` — a bus accepts + events from another account only if its policy grants it. (Same-account, cross-Region + needs only the put-events role above.) + +The forwarded event lands on the agent Region's default bus still carrying +`resources: [""]`, so this stack's rule matches it. + +## Notes + +- **Region availability.** EventBridge API destinations to public HTTPS endpoints are not + available in every AWS Region. Check + [API destinations as targets](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-destinations.html#eb-api-destination-regions) + before deploying into a less common Region. +- **Deduplication.** `incidentId` is the EventBridge event id, which is constant across + retries, so redeliveries of the same event reuse the same `incidentId` and DevOps Agent + correlates them instead of opening duplicates. Repeat/flapping alarms are also + correlated natively; control flapping at the alarm's datapoints-to-alarm setting. +- **Delivery retries and stale events.** The retry policy allows up to 32 attempts over + 8 hours, and `MaximumEventAgeInSeconds` means EventBridge stops trying once an event is + older than that — so a long-delayed redelivery cannot open a stale investigation. +- **Endpoint timeout.** API destinations require the endpoint to respond within 5 seconds. + EventBridge retries timeouts within the retry policy above. +- **Monitoring delivery failures.** There is no function log group to read. The rule + publishes `InvocationAttempts`, `SuccessfulInvocationAttempts`, + `RetryInvocationAttempts` and `FailedInvocations` in the `AWS/Events` namespace, + dimensioned by `RuleName` — alarm on `FailedInvocations`, and watch + `RetryInvocationAttempts` for an endpoint that is struggling but still succeeding. Add + a dead-letter queue to the target if you need to inspect events that never landed. +- **Rotating the API key.** The connection resolves its key when the stack is created or + when the connection resource itself changes. After rotating the webhook, update the + stack with the new `WebhookApiKey` value; the key is not re-read automatically. +- **Keeping the key in your own secret.** If you already store the key in Secrets Manager, + replace the `ApiKeyValue` line in the template with a dynamic reference so the key never + passes through a stack parameter: + ```yaml + ApiKeyValue: '{{resolve:secretsmanager:MyWebhookSecret}}' + ``` + Substitute your secret's name (or full ARN for a cross-account secret), and drop the + `WebhookApiKey` parameter. The same rotation caveat applies: CloudFormation re-resolves + the reference only when the resource is updated. +- **API key versus HMAC.** The DevOps Agent generic webhook also supports HMAC + authentication, which adds payload integrity and replay protection. EventBridge + connections support only Basic, API key, and OAuth, and cannot compute a per-request + signature, so HMAC would require a signing Lambda between the rule and the webhook. + This template takes the API key path to stay code-free; over HTTPS to an AWS endpoint + the bearer token is the simpler trade. 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 0000000..9eff842 --- /dev/null +++ b/cloudformation/devops-agent-alarm-investigations/devops-agent-alarm-investigations.yaml @@ -0,0 +1,220 @@ +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 + - AgentName + - Label: + default: Alarm + Parameters: + - AlarmArn + - Label: + default: Delivery Tuning (optional) + Parameters: + - InvocationRateLimitPerSecond + ParameterLabels: + WebhookUrl: + default: DevOps Agent generic (API key) webhook URL + WebhookApiKey: + default: Webhook API key (bearer token) + AgentName: + default: Target DevOps Agent name (used to tag created resources) + AlarmArn: + default: ARN of the single CloudWatch alarm to forward + InvocationRateLimitPerSecond: + default: Max webhook invocations per second + +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. + + AgentName: + Type: String + Description: > + Name/label of the AWS DevOps Agent this integration targets. Used only to tag + the taggable resources this stack creates (EventBridge rule, IAM role) with + DevOpsAgent= for identification and cost allocation; it does not affect + routing (routing is determined by the webhook URL). + MinLength: 1 + MaxLength: 256 + AllowedPattern: "^[A-Za-z0-9 _.:/=+@-]{1,256}$" + ConstraintDescription: > + 1-256 characters using letters, numbers, spaces, and _ . : / = + - @ + (the AWS tag-value character set). + + 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. + + InvocationRateLimitPerSecond: + Type: Number + Default: 1 + MinValue: 1 + MaxValue: 300 + Description: > + (Optional) Maximum webhook invocations per second for the API destination. The + default of 1 suits a single low-frequency alarm. Raise it only if one stack must + absorb a burst; events above the limit are queued and retried inside the retry + window. + +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 (${AgentName}).' + 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 (${AgentName}).' + 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: !Ref AgentName + + # 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: !Ref AgentName + +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 0000000..e2bf20e --- /dev/null +++ b/cloudformation/devops-agent-skill-policies/README.md @@ -0,0 +1,115 @@ +# 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` | +| `EnableEksOperationReview` | `eks-operation-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/database-migration-service-expertise/README.md b/skills/database-migration-service-expertise/README.md index eb920c5..fb8d0c5 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/msk-operations/README.md b/skills/msk-operations/README.md index cf4686d..a9ff1b4 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: ```