Skip to content

[Rapticore] Security Findings - hamza/RCOR-2712 (Part 1)#42

Draft
rapticore-github[bot] wants to merge 95 commits into
rapticore/tracking-hamza/RCOR-2712-1from
hamza/RCOR-2712
Draft

[Rapticore] Security Findings - hamza/RCOR-2712 (Part 1)#42
rapticore-github[bot] wants to merge 95 commits into
rapticore/tracking-hamza/RCOR-2712-1from
hamza/RCOR-2712

Conversation

@rapticore-github

Copy link
Copy Markdown

Rapticore Security Findings (Part 1)

This is a draft PR containing automated security fix recommendations from Rapticore.

⚠️ This is part 1 of the findings for this branch.

How to use this PR:

  1. Review the suggested fixes in the comments below
  2. Apply fixes manually to your branch or use the provided code snippets
  3. This PR will be automatically updated as new findings are discovered

🤖 Generated by Rapticore

rrrix and others added 30 commits April 21, 2020 12:06
Co-authored-by: Azeem Irshad <azeem.irshad@rapticore.com>
Co-authored-by: Azeem Irshad <azeem.irshad@rapticore.com>
changed the name of the standard cfn to standardsomething
Hamza Arshad and others added 26 commits November 21, 2024 21:36
RCOR-2203: added reactive and one-click remediation permission in cross-account IAM role
RCOR-2240: updated reactive remediation permissions in cross-account IAM role
RCOR-2241: added IAM right-sizing permissions in cross-account IAM role
RCOR-2335: updated one click remediation permissions in cross-account IAM role
RCOR-2361: added guardrails permissions in cross-account IAM role
add queue creation and azure oidc setup in stack
Comment on lines +172 to +234
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: Allow HTTPS traffic
Tags:
- Key: Name
Value: !Sub "${ClusterName}-cluster-sg"

ClusterSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref ClusterSecurityGroup
IpProtocol: "-1"
SourceSecurityGroupId: !Ref ClusterSecurityGroup
Description: Allow cluster internal communication

#####
# EKS Cluster
#####
EksCluster:
Type: AWS::EKS::Cluster
Properties:
Name: !Ref ClusterName
Version: !Ref KubernetesVersion
RoleArn: !GetAtt EksClusterRole.Arn
ResourcesVpcConfig:
SecurityGroupIds:
- !Ref ClusterSecurityGroup
SubnetIds: !Ref SubnetIds
EndpointPublicAccess: !Ref EndpointPublicAccess
EndpointPrivateAccess: !Ref EndpointPrivateAccess
Logging:
ClusterLogging:
EnabledTypes:
- Type: api
- Type: audit
- Type: authenticator
- Type: controllerManager
- Type: scheduler
Tags:
- Key: Name
Value: !Ref ClusterName

#####
# EKS Add-ons
#####
VpcCniAddon:
Type: AWS::EKS::Addon
DependsOn: EksCluster
Properties:
AddonName: vpc-cni
ClusterName: !Ref ClusterName
ResolveConflicts: OVERWRITE
ConfigurationValues: '{"env":{"ENABLE_PREFIX_DELEGATION":"true","WARM_PREFIX_TARGET":"1","MINIMUM_IP_TARGET":"50","WARM_IP_TARGET":"10"}}'

CoreDnsAddon:
Type: AWS::EKS::Addon
DependsOn: EksCluster
Properties:
AddonName: coredns
ClusterName: !Ref ClusterName
ResolveConflicts: OVERWRITE

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security Finding: EKS Secrets Encryption Disabled

Severity: High
Lines: 192-214

Actions

  • Mark as Ignored - Resolve this finding manually (Finding ID: RCOR-0114)

Description

The EKS Cluster does not have Secrets Encryption enabled. This exposes sensitive data to unauthorized access if the cluster is compromised. Secrets encryption is crucial for protecting sensitive data from unauthorized access.

Remediation Summary

Fix Required

  • Add the EncryptionConfig property to the EKS Cluster resource (lines 192-214) to enable secrets encryption
  • Specify the Resources array with secrets as the resource type to encrypt
  • Reference a KMS key ARN (either create a new KMS key or use an existing one) for the encryption provider

Code Pattern

Add this block after the Logging section and before Tags:

EncryptionConfig:
  - Resources:
      - secrets
    Provider:
      KeyArn: !GetAtt EksKmsKey.Arn

Ensure an AWS::KMS::Key resource is defined in the template (or reference an existing KMS key ARN) to serve as the encryption provider.

Verification

Deploy the updated CloudFormation template and confirm the EKS cluster's EncryptionConfig shows secrets encryption is enabled via AWS Console or AWS CLI (aws eks describe-cluster --name <cluster-name> --query cluster.encryptionConfig).

Priority

high - Estimated effort: 10-15 minutes


Suggested Fix

Click "Commit suggestion" to apply this fix:

Suggested change
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: Allow HTTPS traffic
Tags:
- Key: Name
Value: !Sub "${ClusterName}-cluster-sg"
ClusterSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref ClusterSecurityGroup
IpProtocol: "-1"
SourceSecurityGroupId: !Ref ClusterSecurityGroup
Description: Allow cluster internal communication
#####
# EKS Cluster
#####
EksCluster:
Type: AWS::EKS::Cluster
Properties:
Name: !Ref ClusterName
Version: !Ref KubernetesVersion
RoleArn: !GetAtt EksClusterRole.Arn
ResourcesVpcConfig:
SecurityGroupIds:
- !Ref ClusterSecurityGroup
SubnetIds: !Ref SubnetIds
EndpointPublicAccess: !Ref EndpointPublicAccess
EndpointPrivateAccess: !Ref EndpointPrivateAccess
Logging:
ClusterLogging:
EnabledTypes:
- Type: api
- Type: audit
- Type: authenticator
- Type: controllerManager
- Type: scheduler
Tags:
- Key: Name
Value: !Ref ClusterName
#####
# EKS Add-ons
#####
VpcCniAddon:
Type: AWS::EKS::Addon
DependsOn: EksCluster
Properties:
AddonName: vpc-cni
ClusterName: !Ref ClusterName
ResolveConflicts: OVERWRITE
ConfigurationValues: '{"env":{"ENABLE_PREFIX_DELEGATION":"true","WARM_PREFIX_TARGET":"1","MINIMUM_IP_TARGET":"50","WARM_IP_TARGET":"10"}}'
CoreDnsAddon:
Type: AWS::EKS::Addon
DependsOn: EksCluster
Properties:
AddonName: coredns
ClusterName: !Ref ClusterName
ResolveConflicts: OVERWRITE
```yaml
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: Allow HTTPS traffic
Tags:
- Key: Name
Value: !Sub "${ClusterName}-cluster-sg"
ClusterSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref ClusterSecurityGroup
IpProtocol: "-1"
SourceSecurityGroupId: !Ref ClusterSecurityGroup
Description: Allow cluster internal communication
#####
# EKS Cluster
#####
EksCluster:
Type: AWS::EKS::Cluster
Properties:
Name: !Ref ClusterName
Version: !Ref KubernetesVersion
RoleArn: !GetAtt EksClusterRole.Arn
ResourcesVpcConfig:
SecurityGroupIds:
- !Ref ClusterSecurityGroup
SubnetIds: !Ref SubnetIds
EndpointPublicAccess: !Ref EndpointPublicAccess
EndpointPrivateAccess: !Ref EndpointPrivateAccess
Logging:
ClusterLogging:
EnabledTypes:
- Type: api
- Type: audit
- Type: authenticator
- Type: controllerManager
- Type: scheduler
EncryptionConfig:
- Resources:
- secrets
Provider:
KeyArn: !GetAtt EksSecretsEncryptionKey.Arn
Tags:
- Key: Name
Value: !Ref ClusterName
#####
# EKS Add-ons
#####
VpcCniAddon:
Type: AWS::EKS::Addon
DependsOn: EksCluster
Properties:
AddonName: vpc-cni
ClusterName: !Ref ClusterName
ResolveConflicts: OVERWRITE
ConfigurationValues: '{"env":{"ENABLE_PREFIX_DELEGATION":"true","WARM_PREFIX_TARGET":"1","MINIMUM_IP_TARGET":"50","WARM_IP_TARGET":"10"}}'
CoreDnsAddon:
Type: AWS::EKS::Addon
DependsOn: EksCluster
Properties:
AddonName: coredns
ClusterName: !Ref ClusterName
ResolveConflicts: OVERWRITE

---
🤖 Generated by Rapticore

Comment on lines +70 to +141

ClusterEndpoint:
Type: String
Description: EKS cluster API server endpoint (from EksClusterStack)

ClusterCertificateAuthority:
Type: String
Description: EKS cluster certificate authority data, base64 encoded (from EksClusterStack)

ClusterServiceCidr:
Type: String
Default: "10.100.0.0/16"
Description: Kubernetes service IPv4 CIDR (from EksClusterStack)

Resources:
#####
# Launch Template — sets maxPods=110 via nodeadm for AL2023
# Required because prefix delegation increases available IPs but
# the kubelet default max-pods calculation ignores it.
#####
NodeLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref DiskSize
VolumeType: gp3
Encrypted: true
UserData:
Fn::Base64: !Sub |
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="BOUNDARY"

--BOUNDARY
Content-Type: application/node.eks.aws

---
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
cluster:
name: ${ClusterName}
apiServerEndpoint: ${ClusterEndpoint}
certificateAuthority: ${ClusterCertificateAuthority}
cidr: ${ClusterServiceCidr}
kubelet:
config:
maxPods: 110

--BOUNDARY--

#####
# EKS Node Group
#####
EksNodeGroup:
Type: AWS::EKS::Nodegroup
Properties:
ClusterName: !Ref ClusterName
NodeRole: !Ref NodeRoleArn
Subnets: !Ref SubnetIds
ScalingConfig:
DesiredSize: !Ref DesiredSize
MinSize: !Ref MinSize
MaxSize: !Ref MaxSize
InstanceTypes: !Ref InstanceTypes
CapacityType: !Ref CapacityType
AmiType: !Ref AmiType
LaunchTemplate:
Id: !Ref NodeLaunchTemplate
Version: !GetAtt NodeLaunchTemplate.LatestVersionNumber

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security Finding: Instance Metadata Service V1 Enabled

Severity: High
Lines: 90-121

Actions

  • Mark as Ignored - Resolve this finding manually (Finding ID: RCOR-0075)

Description

Instance Metadata Service Version 1 is enabled, which is a security risk. This can allow unauthorized access to instance metadata, leading to potential data exposure and unauthorized actions.

Remediation Summary

Fix Required

• Add MetadataOptions to the LaunchTemplateData section (after line 99, before or after UserData) to disable IMDSv1 and enforce IMDSv2
• Set HttpTokens to 'required' to mandate token-based metadata requests (IMDSv2)
• Set HttpPutResponseHopLimit to '1' to prevent metadata propagation across network hops

Code Pattern

Add this block to LaunchTemplateData:
MetadataOptions:
HttpTokens: required
HttpPutResponseHopLimit: 1

Verification

Deploy the CloudFormation template and verify via AWS Console that the Launch Template's MetadataOptions shows HttpTokens='required', indicating IMDSv2 is enforced and IMDSv1 is disabled.

Priority

high - Estimated effort: 5 minutes


Suggested Fix

Click "Commit suggestion" to apply this fix:

Suggested change
ClusterEndpoint:
Type: String
Description: EKS cluster API server endpoint (from EksClusterStack)
ClusterCertificateAuthority:
Type: String
Description: EKS cluster certificate authority data, base64 encoded (from EksClusterStack)
ClusterServiceCidr:
Type: String
Default: "10.100.0.0/16"
Description: Kubernetes service IPv4 CIDR (from EksClusterStack)
Resources:
#####
# Launch Template — sets maxPods=110 via nodeadm for AL2023
# Required because prefix delegation increases available IPs but
# the kubelet default max-pods calculation ignores it.
#####
NodeLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref DiskSize
VolumeType: gp3
Encrypted: true
UserData:
Fn::Base64: !Sub |
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="BOUNDARY"
--BOUNDARY
Content-Type: application/node.eks.aws
---
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
cluster:
name: ${ClusterName}
apiServerEndpoint: ${ClusterEndpoint}
certificateAuthority: ${ClusterCertificateAuthority}
cidr: ${ClusterServiceCidr}
kubelet:
config:
maxPods: 110
--BOUNDARY--
#####
# EKS Node Group
#####
EksNodeGroup:
Type: AWS::EKS::Nodegroup
Properties:
ClusterName: !Ref ClusterName
NodeRole: !Ref NodeRoleArn
Subnets: !Ref SubnetIds
ScalingConfig:
DesiredSize: !Ref DesiredSize
MinSize: !Ref MinSize
MaxSize: !Ref MaxSize
InstanceTypes: !Ref InstanceTypes
CapacityType: !Ref CapacityType
AmiType: !Ref AmiType
LaunchTemplate:
Id: !Ref NodeLaunchTemplate
Version: !GetAtt NodeLaunchTemplate.LatestVersionNumber
```yaml
ClusterEndpoint:
Type: String
Description: EKS cluster API server endpoint (from EksClusterStack)
ClusterCertificateAuthority:
Type: String
Description: EKS cluster certificate authority data, base64 encoded (from EksClusterStack)
ClusterServiceCidr:
Type: String
Default: "10.100.0.0/16"
Description: Kubernetes service IPv4 CIDR (from EksClusterStack)
Resources:
#####
# Launch Template — sets maxPods=110 via nodeadm for AL2023
# Required because prefix delegation increases available IPs but
# the kubelet default max-pods calculation ignores it.
#####
NodeLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
MetadataOptions:
HttpEndpoint: enabled
HttpTokens: required
HttpPutResponseHopLimit: 1
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: !Ref DiskSize
VolumeType: gp3
Encrypted: true
UserData:
Fn::Base64: !Sub |
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="BOUNDARY"
--BOUNDARY
Content-Type: application/node.eks.aws
---
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
cluster:
name: ${ClusterName}
apiServerEndpoint: ${ClusterEndpoint}
certificateAuthority: ${ClusterCertificateAuthority}
cidr: ${ClusterServiceCidr}
kubelet:
config:
maxPods: 110
--BOUNDARY--
#####
# EKS Node Group
#####
EksNodeGroup:
Type: AWS::EKS::Nodegroup
Properties:
ClusterName: !Ref ClusterName
NodeRole: !Ref NodeRoleArn
Subnets: !Ref SubnetIds
ScalingConfig:
DesiredSize: !Ref DesiredSize
MinSize: !Ref MinSize
MaxSize: !Ref MaxSize
InstanceTypes: !Ref InstanceTypes
CapacityType: !Ref CapacityType
AmiType: !Ref AmiType
LaunchTemplate:
Id: !Ref NodeLaunchTemplate
Version: !GetAtt NodeLaunchTemplate.LatestVersionNumber

---
🤖 Generated by Rapticore

Comment on lines +376 to +575
Action:
- sts:AssumeRole
- sts:TagSession
Resource: "arn:aws:iam::*:role/rapticore-cross-account-*"
# IAM and EC2 Read-Only (needed by discovery for role enumeration)
- Effect: Allow
Action:
- iam:ListRole*
- iam:GetRole*
- ec2:DescribeRegions
Resource: "*"
# Cognito Identity (needed for Azure workload identity)
- Effect: Allow
Action:
- cognito-identity:GetOpenIdTokenForDeveloperIdentity
Resource: !Sub "arn:aws:cognito-identity:${AWS::Region}:${AWS::AccountId}:identitypool/*"

#####
# AWS Load Balancer Controller IAM Role (IRSA)
#####
AwsLoadBalancerControllerRole:
Type: AWS::IAM::Role
DependsOn: OidcProvider
Properties:
RoleName: !Sub "${ClusterName}-aws-load-balancer-controller-role"
AssumeRolePolicyDocument:
Fn::Sub:
- |
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${OidcUrl}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OidcUrl}:aud": "sts.amazonaws.com",
"${OidcUrl}:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
}
}
}]
}
- OidcUrl: !Select [1, !Split ["https://", !GetAtt EksCluster.OpenIdConnectIssuerUrl]]
Policies:
- PolicyName: AWSLoadBalancerControllerPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- iam:CreateServiceLinkedRole
Resource: "*"
Condition:
StringEquals:
iam:AWSServiceName: elasticloadbalancing.amazonaws.com
- Effect: Allow
Action:
- ec2:DescribeAccountAttributes
- ec2:DescribeAddresses
- ec2:DescribeAvailabilityZones
- ec2:DescribeInternetGateways
- ec2:DescribeVpcs
- ec2:DescribeVpcPeeringConnections
- ec2:DescribeSubnets
- ec2:DescribeSecurityGroups
- ec2:DescribeInstances
- ec2:DescribeNetworkInterfaces
- ec2:DescribeTags
- ec2:DescribeRouteTables
- ec2:GetCoipPoolUsage
- ec2:DescribeCoipPools
- elasticloadbalancing:DescribeLoadBalancers
- elasticloadbalancing:DescribeLoadBalancerAttributes
- elasticloadbalancing:DescribeListeners
- elasticloadbalancing:DescribeListenerAttributes
- elasticloadbalancing:DescribeListenerCertificates
- elasticloadbalancing:DescribeSSLPolicies
- elasticloadbalancing:DescribeRules
- elasticloadbalancing:DescribeTargetGroups
- elasticloadbalancing:DescribeTargetGroupAttributes
- elasticloadbalancing:DescribeTargetHealth
- elasticloadbalancing:DescribeTags
Resource: "*"
- Effect: Allow
Action:
- cognito-idp:DescribeUserPoolClient
- acm:ListCertificates
- acm:DescribeCertificate
- iam:ListServerCertificates
- iam:GetServerCertificate
- waf-regional:GetWebACL
- waf-regional:GetWebACLForResource
- waf-regional:AssociateWebACL
- waf-regional:DisassociateWebACL
- wafv2:GetWebACL
- wafv2:GetWebACLForResource
- wafv2:AssociateWebACL
- wafv2:DisassociateWebACL
- shield:GetSubscriptionState
- shield:DescribeProtection
- shield:CreateProtection
- shield:DeleteProtection
Resource: "*"
- Effect: Allow
Action:
- ec2:AuthorizeSecurityGroupIngress
- ec2:RevokeSecurityGroupIngress
Resource: "*"
- Effect: Allow
Action:
- ec2:CreateSecurityGroup
Resource: "*"
- Effect: Allow
Action:
- ec2:CreateTags
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
StringEquals:
ec2:CreateAction: CreateSecurityGroup
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- ec2:CreateTags
- ec2:DeleteTags
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "true"
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- ec2:AuthorizeSecurityGroupIngress
- ec2:RevokeSecurityGroupIngress
- ec2:DeleteSecurityGroup
Resource: "*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:CreateLoadBalancer
- elasticloadbalancing:CreateTargetGroup
Resource: "*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:CreateListener
- elasticloadbalancing:DeleteListener
- elasticloadbalancing:CreateRule
- elasticloadbalancing:DeleteRule
Resource: "*"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "true"
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*"
- Effect: Allow
Action:
- elasticloadbalancing:ModifyLoadBalancerAttributes
- elasticloadbalancing:SetIpAddressType
- elasticloadbalancing:SetSecurityGroups
- elasticloadbalancing:SetSubnets
- elasticloadbalancing:DeleteLoadBalancer
- elasticloadbalancing:ModifyTargetGroup
- elasticloadbalancing:ModifyTargetGroupAttributes
- elasticloadbalancing:DeleteTargetGroup
Resource: "*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
Condition:
StringEquals:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security Finding: IAM Policy Allows Unsafe Write Access

Severity: High
Lines: 396-593

Actions

  • Mark as Ignored - Resolve this finding manually (Finding ID: RCOR-0019)

Description

The IAM policy allows write access without necessary constraints, which can lead to unauthorized modifications. This can compromise the security and integrity of the associated resources. The impact includes potential data leaks or unauthorized changes to critical infrastructure.

Remediation Summary

Fix Required

Remove or constrain overly permissive write actions: Several statements allow write operations (CreateSecurityGroup, AuthorizeSecurityGroupIngress, CreateLoadBalancer, ModifyListener, etc.) with Resource: "*" or insufficient conditions. These must be scoped to specific ARNs or have resource-level constraints.

Add resource ARN constraints to write statements: Lines with write actions lacking proper conditions should specify exact ARN patterns. For example, ec2:AuthorizeSecurityGroupIngress and ec2:RevokeSecurityGroupIngress (lines 76-80) have Resource: "*" with only a Condition tag check—add ARN restrictions like arn:aws:ec2:*:*:security-group/*.

Scope listener/rule modifications: The statement at the end (elasticloadbalancing:SetWebAcl, ModifyListener, AddListenerCertificates, RemoveListenerCertificates, ModifyRule) has Resource: "*" with no conditions. Add ARN-based resource restrictions or introduce conditions that limit modifications to cluster-tagged resources.

Code Pattern

For write actions without proper scoping, apply this pattern:

- Effect: Allow
  Action:
    - ec2:AuthorizeSecurityGroupIngress
    - ec2:RevokeSecurityGroupIngress
  Resource: "arn:aws:ec2:*:*:security-group/*"
  Condition:
    "Null":
      aws:ResourceTag/elbv2.k8s.aws/cluster: "false"

For ELB operations, restrict to tagged resources:

- Effect: Allow
  Action:
    - elasticloadbalancing:ModifyListener
    - elasticloadbalancing:SetWebAcl
  Resource:
    - "arn:aws:elasticloadbalancing:*:*:listener/*"
    - "arn:aws:elasticloadbalancing:*:*:loadbalancer/*"
  Condition:
    "Null":
      aws:ResourceTag/elbv2.k8s.aws/cluster: "false"

Verification

Validate that all write-capable actions (Create*, Modify*, Delete*, Authorize*, Set*) either have specific ARN patterns in Resource field or have Condition blocks referencing resource tags/request tags to prevent unrestricted modifications.

Priority

high - Estimated effort: 20 minutes


Suggested Fix

Click "Commit suggestion" to apply this fix:

Suggested change
Action:
- sts:AssumeRole
- sts:TagSession
Resource: "arn:aws:iam::*:role/rapticore-cross-account-*"
# IAM and EC2 Read-Only (needed by discovery for role enumeration)
- Effect: Allow
Action:
- iam:ListRole*
- iam:GetRole*
- ec2:DescribeRegions
Resource: "*"
# Cognito Identity (needed for Azure workload identity)
- Effect: Allow
Action:
- cognito-identity:GetOpenIdTokenForDeveloperIdentity
Resource: !Sub "arn:aws:cognito-identity:${AWS::Region}:${AWS::AccountId}:identitypool/*"
#####
# AWS Load Balancer Controller IAM Role (IRSA)
#####
AwsLoadBalancerControllerRole:
Type: AWS::IAM::Role
DependsOn: OidcProvider
Properties:
RoleName: !Sub "${ClusterName}-aws-load-balancer-controller-role"
AssumeRolePolicyDocument:
Fn::Sub:
- |
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${OidcUrl}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OidcUrl}:aud": "sts.amazonaws.com",
"${OidcUrl}:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
}
}
}]
}
- OidcUrl: !Select [1, !Split ["https://", !GetAtt EksCluster.OpenIdConnectIssuerUrl]]
Policies:
- PolicyName: AWSLoadBalancerControllerPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- iam:CreateServiceLinkedRole
Resource: "*"
Condition:
StringEquals:
iam:AWSServiceName: elasticloadbalancing.amazonaws.com
- Effect: Allow
Action:
- ec2:DescribeAccountAttributes
- ec2:DescribeAddresses
- ec2:DescribeAvailabilityZones
- ec2:DescribeInternetGateways
- ec2:DescribeVpcs
- ec2:DescribeVpcPeeringConnections
- ec2:DescribeSubnets
- ec2:DescribeSecurityGroups
- ec2:DescribeInstances
- ec2:DescribeNetworkInterfaces
- ec2:DescribeTags
- ec2:DescribeRouteTables
- ec2:GetCoipPoolUsage
- ec2:DescribeCoipPools
- elasticloadbalancing:DescribeLoadBalancers
- elasticloadbalancing:DescribeLoadBalancerAttributes
- elasticloadbalancing:DescribeListeners
- elasticloadbalancing:DescribeListenerAttributes
- elasticloadbalancing:DescribeListenerCertificates
- elasticloadbalancing:DescribeSSLPolicies
- elasticloadbalancing:DescribeRules
- elasticloadbalancing:DescribeTargetGroups
- elasticloadbalancing:DescribeTargetGroupAttributes
- elasticloadbalancing:DescribeTargetHealth
- elasticloadbalancing:DescribeTags
Resource: "*"
- Effect: Allow
Action:
- cognito-idp:DescribeUserPoolClient
- acm:ListCertificates
- acm:DescribeCertificate
- iam:ListServerCertificates
- iam:GetServerCertificate
- waf-regional:GetWebACL
- waf-regional:GetWebACLForResource
- waf-regional:AssociateWebACL
- waf-regional:DisassociateWebACL
- wafv2:GetWebACL
- wafv2:GetWebACLForResource
- wafv2:AssociateWebACL
- wafv2:DisassociateWebACL
- shield:GetSubscriptionState
- shield:DescribeProtection
- shield:CreateProtection
- shield:DeleteProtection
Resource: "*"
- Effect: Allow
Action:
- ec2:AuthorizeSecurityGroupIngress
- ec2:RevokeSecurityGroupIngress
Resource: "*"
- Effect: Allow
Action:
- ec2:CreateSecurityGroup
Resource: "*"
- Effect: Allow
Action:
- ec2:CreateTags
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
StringEquals:
ec2:CreateAction: CreateSecurityGroup
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- ec2:CreateTags
- ec2:DeleteTags
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "true"
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- ec2:AuthorizeSecurityGroupIngress
- ec2:RevokeSecurityGroupIngress
- ec2:DeleteSecurityGroup
Resource: "*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:CreateLoadBalancer
- elasticloadbalancing:CreateTargetGroup
Resource: "*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:CreateListener
- elasticloadbalancing:DeleteListener
- elasticloadbalancing:CreateRule
- elasticloadbalancing:DeleteRule
Resource: "*"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "true"
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*"
- Effect: Allow
Action:
- elasticloadbalancing:ModifyLoadBalancerAttributes
- elasticloadbalancing:SetIpAddressType
- elasticloadbalancing:SetSecurityGroups
- elasticloadbalancing:SetSubnets
- elasticloadbalancing:DeleteLoadBalancer
- elasticloadbalancing:ModifyTargetGroup
- elasticloadbalancing:ModifyTargetGroupAttributes
- elasticloadbalancing:DeleteTargetGroup
Resource: "*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
Condition:
StringEquals:
```yaml
Action:
- sts:AssumeRole
- sts:TagSession
Resource: "arn:aws:iam::*:role/rapticore-cross-account-*"
# IAM and EC2 Read-Only (needed by discovery for role enumeration)
- Effect: Allow
Action:
- iam:ListRole*
- iam:GetRole*
- ec2:DescribeRegions
Resource: "*"
# Cognito Identity (needed for Azure workload identity)
- Effect: Allow
Action:
- cognito-identity:GetOpenIdTokenForDeveloperIdentity
Resource: !Sub "arn:aws:cognito-identity:${AWS::Region}:${AWS::AccountId}:identitypool/*"
#####
# AWS Load Balancer Controller IAM Role (IRSA)
#####
AwsLoadBalancerControllerRole:
Type: AWS::IAM::Role
DependsOn: OidcProvider
Properties:
RoleName: !Sub "${ClusterName}-aws-load-balancer-controller-role"
AssumeRolePolicyDocument:
Fn::Sub:
- |
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${OidcUrl}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OidcUrl}:aud": "sts.amazonaws.com",
"${OidcUrl}:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
}
}
}]
}
- OidcUrl: !Select [1, !Split ["https://", !GetAtt EksCluster.OpenIdConnectIssuerUrl]]
Policies:
- PolicyName: AWSLoadBalancerControllerPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- iam:CreateServiceLinkedRole
Resource: "*"
Condition:
StringEquals:
iam:AWSServiceName: elasticloadbalancing.amazonaws.com
- Effect: Allow
Action:
- ec2:DescribeAccountAttributes
- ec2:DescribeAddresses
- ec2:DescribeAvailabilityZones
- ec2:DescribeInternetGateways
- ec2:DescribeVpcs
- ec2:DescribeVpcPeeringConnections
- ec2:DescribeSubnets
- ec2:DescribeSecurityGroups
- ec2:DescribeInstances
- ec2:DescribeNetworkInterfaces
- ec2:DescribeTags
- ec2:DescribeRouteTables
- ec2:GetCoipPoolUsage
- ec2:DescribeCoipPools
- elasticloadbalancing:DescribeLoadBalancers
- elasticloadbalancing:DescribeLoadBalancerAttributes
- elasticloadbalancing:DescribeListeners
- elasticloadbalancing:DescribeListenerAttributes
- elasticloadbalancing:DescribeListenerCertificates
- elasticloadbalancing:DescribeSSLPolicies
- elasticloadbalancing:DescribeRules
- elasticloadbalancing:DescribeTargetGroups
- elasticloadbalancing:DescribeTargetGroupAttributes
- elasticloadbalancing:DescribeTargetHealth
- elasticloadbalancing:DescribeTags
Resource: "*"
- Effect: Allow
Action:
- cognito-idp:DescribeUserPoolClient
- acm:ListCertificates
- acm:DescribeCertificate
- iam:ListServerCertificates
- iam:GetServerCertificate
- waf-regional:GetWebACL
- waf-regional:GetWebACLForResource
- wafv2:GetWebACL
- wafv2:GetWebACLForResource
- shield:GetSubscriptionState
- shield:DescribeProtection
Resource: "*"
- Effect: Allow
Action:
- ec2:AuthorizeSecurityGroupIngress
- ec2:RevokeSecurityGroupIngress
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- ec2:CreateSecurityGroup
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
StringEquals:
ec2:Vpc: !Sub "arn:aws:ec2:*:${AWS::AccountId}:vpc/*"
- Effect: Allow
Action:
- ec2:CreateTags
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
StringEquals:
ec2:CreateAction: CreateSecurityGroup
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- ec2:CreateTags
- ec2:DeleteTags
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "true"
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- ec2:DeleteSecurityGroup
Resource: "arn:aws:ec2:*:*:security-group/*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:CreateLoadBalancer
- elasticloadbalancing:CreateTargetGroup
Resource: "*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:CreateListener
- elasticloadbalancing:DeleteListener
- elasticloadbalancing:CreateRule
- elasticloadbalancing:DeleteRule
Resource: "arn:aws:elasticloadbalancing:*:*:listener*/app/*/*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*"
- "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*"
Condition:
"Null":
aws:RequestTag/elbv2.k8s.aws/cluster: "true"
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
Resource:
- "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*"
- "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:ModifyLoadBalancerAttributes
- elasticloadbalancing:SetIpAddressType
- elasticloadbalancing:SetSecurityGroups
- elasticloadbalancing:SetSubnets
- elasticloadbalancing:DeleteLoadBalancer
- elasticloadbalancing:ModifyTargetGroup
- elasticloadbalancing:ModifyTargetGroupAttributes
- elasticloadbalancing:DeleteTargetGroup
Resource: "*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:AddTags
Resource:

🤖 Generated by Rapticore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants