I found an answer to this. I think the following policy is not well-tuned, and may miss certain edge cases.
It did work for what I need - albeit not yet robustly for a 'do anything' sandbox. I'm posting it so it might help others.
If anyone develops a complete answer, I'd be glad to accept theirs
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "I can tag myself",
"Effect": "Allow",
"Action": "ec2:CreateTags",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "create and tag my roles",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:TagRole"
],
"Resource": "arn:aws:iam::*:role/*",
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "AllowDescribeRoles",
"Effect": "Allow",
"Action": [
"iam:ListRoles",
"iam:ListRoleTags"
],
"Resource": "*"
},
{
"Sid": "AllowDescribeTaggedRoles",
"Effect": "Allow",
"Action": "iam:GetRole",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "AllowAttachRolePolicy",
"Effect": "Allow",
"Action": "iam:AttachRolePolicy",
"Resource": "arn:aws:iam::*:role/*",
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "ServiceLinkedRoles to my RDS",
"Effect": "Allow",
"Action": "iam:CreateServiceLinkedRole",
"Resource": "arn:aws:iam::*:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS",
"Condition": {
"StringLike": {
"iam:AWSServiceName": "redshift.amazonaws.com"
},
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "ServiceLinkedRoles to my RDS",
"Effect": "Allow",
"Action": "iam:CreateServiceLinkedRole",
"Resource": "arn:aws:iam::*:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS",
"Condition": {
"StringLike": {
"iam:AWSServiceName": "rds.amazonaws.com"
},
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "View and Change Own Policies",
"Effect": "Allow",
"Action": [
"iam:ListPolicies",
"iam:ListPolicyTags",
"iam:GetPolicy",
"iam:TagPolicy",
"iam:CreatePolicy",
"iam:CreatePolicyVersion",
"iam:DeletePolicy",
"iam:UpdateAssumeRolePolicy",
"iam:AttachUserPolicy",
"iam:AttachRolePolicy",
"iam:ListAttachedRolePolicies",
"iam:ListRolePolicies",
"iam:GetRolePolicy",
"access-analyzer:*Policy*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Effect": "Allow",
"Action": [
"organizations:DescribeAccount",
"organizations:DescribeOrganization"
],
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:user/${aws:username}"
}
}
},
{
"Sid": "create my own RDS",
"Effect": "Allow",
"Action": [
"rds:*",
"rds:DescribeDBEngineVersions",
"rds:DescribeOrderableDBInstanceOptions",
"rds:CreateDBInstance",
"rds:CreateDBCluster"
],
"Resource": [
"arn:aws:iam::*:role/AWSReservedSSO_*",
"arn:aws:rds:*:*:db:*"
],
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "Allow my S3",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "No STS on Prod",
"Effect": "Allow",
"Action": [
"sts:AssumeRole",
"sts:TagSession"
],
"Resource": [
"arn:aws:rds:*:*:db*",
"arn:aws:s3:::*"
],
"Condition": {
"ForAnyValue:StringNotEquals": {
"aws:RequestTag/environment": "prod"
}
}
},
{
"Sid": "AllowUserTagSandboxedDatabaseAdministratorAccess",
"Effect": "Allow",
"Action": [
"iam:PassRole",
"rds:*"
],
"Resource": [
"arn:aws:iam::*:role/AWSReservedSSO_*",
"arn:aws:rds:*:*:db:*",
"arn:aws:rds:*:*:*:*"
]
},
{
"Sid": "AllowUserTagSandboxedDatabaseAdministratorResources",
"Effect": "Allow",
"Action": [
"rds:*",
"secretsmanager:*",
"kms:*",
"cloudwatch:GetMetricStatistics",
"cloudwatch:DescribeAlarms",
"cloudwatch:ListMetrics",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogStreams",
"logs:PutLogEvents",
"logs:PutMetricFilter",
"logs:PutRetentionPolicy",
"logs:TestMetricFilter",
"sns:Publish",
"sns:ListTopics",
"sns:ListSubscriptionsByTopic"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "AllowUserTagSandboxedDescribeClusters",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"rds:DescribeGlobalClusters"
],
"Resource": [
"arn:aws:rds:*:*:db:*",
"arn:aws:rds:*:*:cluster:*",
"arn:aws:rds::*:global-cluster:*"
],
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "RedshiftCreate",
"Effect": "Allow",
"Action": [
"redshift-serverless:*",
"redshift:*",
"sqlworkbench:*"
],
"Resource": [
"arn:aws:redshift:*:*:*:*",
"arn:aws:redshift-serverless:*:*:*:*",
"arn:aws:sqlworkbench:*:*:*:*"
],
"Condition": {
"StringEquals": {
"aws:RequestTag/CreatedByUser": "${aws:username}"
}
}
},
{
"Sid": "semi-excessive list/get actions group",
"Effect": "Allow",
"Action": [
"iam:List*",
"iam:Get*",
"iam:SimulatePrincipalPolicy",
"iam:SimulateCustomPolicy"
],
"Resource": "*"
}
]
}