aws-scheduler: ScheduleGroup.grantReadSchedules scopes ListSchedules to group ARN, but Scheduler authorizes schedule/*/*
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
## Describe the bug
`ScheduleGroup.grantReadSchedules()` grants `scheduler:ListSchedules` on a group-scoped schedule ARN:
```json
{
"Action": [
"scheduler:CreateSchedule",
"scheduler:GetSchedule",
"scheduler:ListSchedules",
"scheduler:UpdateSchedule"
],
"Resource": "arn:aws:scheduler:::schedule//*",
"Effect": "Allow"
}
```
However, a call to `ListSchedules` with `ScheduleGroup=` fails with an IAM denial on `schedule/*/*`:
```text
User: arn:aws:sts:::assumed-role//
is not authorized to perform: scheduler:ListSchedules on resource:
arn:aws:scheduler:::schedule/*/*
because no identity-based policy allows the scheduler:ListSchedules action
```
This is different from https://github.com/aws/aws-cdk/issues/36165. That issue was about CDK generating `schedule-group//*` instead of `schedule//*`. In this case, CDK generates the expected group-scoped schedule ARN, but EventBridge Scheduler still evaluates `ListSchedules` against `schedule/*/*`.
## Regression Issue
- [ ] Select this option if this issue appears to be a regression.
## Last Known Working CDK Library Version
Not known.
## Expected Behavior
Either:
- `ScheduleGroup.grantReadSchedules()` should grant `scheduler:ListSchedules` on a resource shape accepted by EventBridge Scheduler, or
- `ListSchedules` should not be included in the group-scoped grant if it cannot be scoped to a schedule group.
## Current Behavior
CDK grants `ListSchedules` on:
```text
arn:aws:scheduler:::schedule//*
```
but EventBridge Scheduler authorizes the call against:
```text
arn:aws:scheduler:::schedule/*/*
```
Observed stack trace:
```text
Amazon.Scheduler.AmazonSchedulerException: User: arn:aws:sts:::assumed-role// is not authorized to perform: scheduler:ListSchedules on resource: arn:aws:scheduler:::schedule/*/* because no identity-based policy allows the scheduler:ListSchedules action
---> Amazon.Runtime.Internal.HttpErrorResponseException: Exception of type 'Amazon.Runtime.Internal.HttpErrorResponseException' was thrown.
at Amazon.Runtime.HttpWebRequestMessage.ProcessHttpResponseMessage(HttpResponseMessage responseMessage)
at Amazon.Runtime.HttpWebRequestMessage.GetResponseAsync(CancellationToken cancellationToken)
at Amazon.Runtime.Internal.HttpHandler`1.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.Unmarshaller.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.ErrorHandler.InvokeAsync[T](IExecutionContext executionContext)
--- End of inner exception stack trace ---
at Amazon.Runtime.Internal.HttpErrorResponseExceptionHandler.HandleExceptionStream(IRequestContext requestContext, IWebResponseData httpErrorResponse, HttpErrorResponseException exception, Stream responseStream)
at Amazon.Runtime.Internal.HttpErrorResponseExceptionHandler.HandleExceptionAsync(IExecutionContext executionContext, HttpErrorResponseException exception)
at Amazon.Runtime.Internal.ExceptionHandler`1.HandleAsync(IExecutionContext executionContext, Exception exception)
at Amazon.Runtime.Internal.ErrorHandler.ProcessExceptionAsync(IExecutionContext executionContext, Exception exception)
at Amazon.Runtime.Internal.ErrorHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.Signer.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.EndpointDiscoveryHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.BaseAuthResolverHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.Marshaller.InvokeAsync[T](IExecutionContext executionContext)
```
## Reproduction Steps
Create a schedule group and grant read schedules to a Lambda role:
```ts
import * as scheduler from 'aws-cdk-lib/aws-scheduler';
const group = new scheduler.ScheduleGroup(this, 'Group', {
scheduleGroupName: 'my-group',
});
group.grantReadSchedules(myFunction);
```
This grants `scheduler:ListSchedules` on:
```text
arn:aws:scheduler:::schedule/my-group/*
```
Then call `ListSchedules` with the group filter.
Equivalent .NET SDK call:
```csharp
await schedulerClient.ListSchedulesAsync(new ListSchedulesRequest
{
GroupName = "my-group"
});
```
The .NET SDK marshaller sends:
```text
GET /schedules?ScheduleGroup=my-group
```
but the service denies access unless the role also has `scheduler:ListSchedules` on `schedule/*/*` or `*`.
## Possible Solution
Grant `scheduler:ListSchedules` separately on `*` / `schedule/*/*`, or remove it from `ScheduleGroup.grantReadSchedules()` and document that listing schedules is not group-resource-scoped.
The EventBridge Scheduler API reference documents `ScheduleGroup` as a query filter for `ListSchedules`:
https://docs.aws.amazon.com/scheduler/latest/APIReference/API_ListSchedules.html
The IAM service authorization reference does not list a resource type for `ListSchedules`, which may mean this action should require `Resource: "*"`:
https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazoneventbridgescheduler.html
## Additional Information/Context
Actual generated permission:
```json
{
"Action": [
"scheduler:CreateSchedule",
"scheduler:GetSchedule",
"scheduler:ListSchedules",
"scheduler:UpdateSchedule"
],
"Resource": "arn:aws:scheduler:eu-central-1::schedule//*",
"Effect": "Allow"
}
```
The Lambda environment variable used for the SDK request is set to the same group name:
```text
SchedulerGroupOrderCreationSchedule=
```
The AWS SDK .NET marshaller was checked locally and produced:
```text
ResourcePath=/schedules
HttpMethod=GET
UseQueryString=True
Parameters:
ScheduleGroup=
```
## AWS CDK Library version (aws-cdk-lib)
`Amazon.CDK.Lib 2.235.1` (.NET package; this project does not use `npm ls aws-cdk-lib`).
## AWS CDK CLI version
```text
2.1126.0 (build a90d578)
```
## Node.js Version
```text
v24.15.0
```
## OS
```text
Windows
```
## Language
```text
.NET
```
## Language Version
```text
.NET SDK 10.0.301
```
## Other information
Related issue with a different root cause: https://github.com/aws/aws-cdk/issues/36165
Contributor guide
Research direction
Start by inspecting ScheduleGroup.grantReadSchedules() in the AWS CDK scheduler implementation and its associated tests, then compare the generated policy with the EventBridge Scheduler IAM service authorization reference. Reproduce the ListSchedules call using the group filter and verify that the completed change either grants a service-accepted resource or excludes the action from the group-scoped grant.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- cloud, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100