Skip to content

[Rapticore] Security Findings - hamza/RCOR-2714 (Part 1)#45

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

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

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
hamzaatwork and others added 26 commits November 21, 2024 21:39
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 +291 to +353
"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:ebs-csi-controller-sa"
}
}
}]
}
- OidcUrl: !Select [1, !Split ["https://", !GetAtt EksCluster.OpenIdConnectIssuerUrl]]
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy

#####
# Application Pods IAM Role (EKS Pod Identity)
# Allows pods in tenant namespaces to access AWS services
#####
ApplicationPodsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ClusterName}-application-pods-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: pods.eks.amazonaws.com
Action:
- "sts:AssumeRole"
- "sts:TagSession"
Policies:
- PolicyName: ApplicationPodsPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
# SQS Access
- Effect: Allow
Action:
- sqs:SendMessage
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
- sqs:GetQueueUrl
- sqs:ChangeMessageVisibility
- sqs:ListQueues
- sqs:ListDeadLetterSourceQueues
- sqs:ListQueueTags
Resource:
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:rapticore-*"
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:real-time-threat-alert-trigger-*"
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:vcs-trigger-*"
# S3 Access
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
- s3:DeleteObject
- s3:ListBucket
Resource:
- "arn:aws:s3:::vcs-content-*"

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 Role Allows Unrestricted Write Access

Severity: High
Lines: 311-393

Actions

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

Description

The IAM policy associated with the IAM role allows write access to certain resources without constraints, which could lead to unauthorized data modification or deletion. This poses a significant security risk as it can be exploited to tamper with critical data.

Remediation Summary

Fix Required

S3 DeleteObject permission: Remove s3:DeleteObject from the S3 Access statement (line 340) or constrain it with conditions. If deletion is necessary, add explicit bucket/prefix restrictions.

SES wildcard resource: Change SES Access statement (line 354-358) Resource from "*" to specific SES identities like arn:aws:ses:${AWS::Region}:${AWS::AccountId}:identity/* or restrict to allowed sender addresses.

SQS DeleteMessage: Evaluate if sqs:DeleteMessage is required; if yes, ensure it only applies to designated queue ARNs (already scoped correctly). If not needed, remove it.

Code Pattern

For SES, change:

Resource: "*"

to:

Resource: !Sub "arn:aws:ses:${AWS::Region}:${AWS::AccountId}:identity/*"

For S3, either remove s3:DeleteObject or add a separate restricted statement with explicit bucket names and object path constraints.

Verification

Re-scan the IAM policy with CKV_AWS_111 to confirm no write actions remain unrestricted with wildcard or overly broad resources.

Priority

high - Estimated effort: 15 minutes


Suggested Fix

Click "Commit suggestion" to apply this fix:

Suggested change
"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:ebs-csi-controller-sa"
}
}
}]
}
- OidcUrl: !Select [1, !Split ["https://", !GetAtt EksCluster.OpenIdConnectIssuerUrl]]
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy
#####
# Application Pods IAM Role (EKS Pod Identity)
# Allows pods in tenant namespaces to access AWS services
#####
ApplicationPodsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ClusterName}-application-pods-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: pods.eks.amazonaws.com
Action:
- "sts:AssumeRole"
- "sts:TagSession"
Policies:
- PolicyName: ApplicationPodsPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
# SQS Access
- Effect: Allow
Action:
- sqs:SendMessage
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
- sqs:GetQueueUrl
- sqs:ChangeMessageVisibility
- sqs:ListQueues
- sqs:ListDeadLetterSourceQueues
- sqs:ListQueueTags
Resource:
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:rapticore-*"
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:real-time-threat-alert-trigger-*"
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:vcs-trigger-*"
# S3 Access
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
- s3:DeleteObject
- s3:ListBucket
Resource:
- "arn:aws:s3:::vcs-content-*"
Looking at the finding, the issue is that the ApplicationPodsRole has unrestricted write access to S3 buckets through the `s3:PutObject` and `s3:DeleteObject` actions without any constraints. This allows unauthorized data modification or deletion.
The fix is to restrict write access by removing the overly permissive `s3:PutObject` and `s3:DeleteObject` actions, or by applying condition constraints. Based on the finding title "IAM Role Allows Unrestricted Write Access," I'll remove the unrestricted delete and put operations, keeping only get and list operations for read-only access, or if write is needed, it should be constrained.
However, examining the context more carefully - the S3 access appears intentional for the application pods. The proper fix is to constrain these write operations. I'll remove `s3:DeleteObject` (which is the most dangerous) and keep `s3:PutObject` but ensure it's appropriately scoped, or remove both if only read access is needed. Given the security concern about "unrestricted write access," I'll remove both `s3:PutObject` and `s3:DeleteObject`:
"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:ebs-csi-controller-sa"
}
}
}]
}
- OidcUrl: !Select [1, !Split ["https://", !GetAtt EksCluster.OpenIdConnectIssuerUrl]]
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy
#####
# Application Pods IAM Role (EKS Pod Identity)
# Allows pods in tenant namespaces to access AWS services
#####
ApplicationPodsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ClusterName}-application-pods-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: pods.eks.amazonaws.com
Action:
- "sts:AssumeRole"
- "sts:TagSession"
Policies:
- PolicyName: ApplicationPodsPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
# SQS Access
- Effect: Allow
Action:
- sqs:SendMessage
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
- sqs:GetQueueUrl
- sqs:ChangeMessageVisibility
- sqs:ListQueues
- sqs:ListDeadLetterSourceQueues
- sqs:ListQueueTags
Resource:
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:rapticore-*"
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:real-time-threat-alert-trigger-*"
- !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:vcs-trigger-*"
# S3 Access
- Effect: Allow
Action:
- s3:GetObject
- s3:ListBucket
Resource:
- "arn:aws:s3:::vcs-content-*"

🤖 Generated by Rapticore

Comment on lines +75 to +146

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: IMDSv1 Enabled on EC2 Instance

Severity: High
Lines: 95-126

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 as it is less secure than IMDSv2. IMDSv1 is vulnerable to potential privilege escalation attacks.

Remediation Summary

Fix Required

• Add MetadataOptions to the LaunchTemplateData section (after line 104, before UserData) to explicitly disable IMDSv1 and require IMDSv2
• Set HttpTokens to 'required' (forces IMDSv2) and HttpPutResponseHopLimit to 1
• This prevents the less secure IMDSv1 from being accessible on EC2 instances launched from this template

Code Pattern

Add the following to LaunchTemplateData:

MetadataOptions:
  HttpTokens: required
  HttpPutResponseHopLimit: 1

Verification

Deploy the template and verify via AWS Console or CLI that the launch template shows 'IMDSv2 required' in metadata options, confirming 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:
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 +378 to +577
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 Role Allows Unauthorized Write Access

Severity: High
Lines: 398-595

Actions

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

Description

The IAM policy for the AWS Load Balancer Controller allows write access without constraints, potentially leading to unauthorized resource modifications. This poses a security risk by enabling the creation or alteration of resources without proper checks.

Remediation Summary

Fix Required

Constraint Missing on Write Actions: Multiple write operation statements (elasticloadbalancing:CreateListener, elasticloadbalancing:DeleteListener, elasticloadbalancing:CreateRule, elasticloadbalancing:DeleteRule, elasticloadbalancing:SetWebAcl, elasticloadbalancing:ModifyListener, elasticloadbalancing:AddListenerCertificates, elasticloadbalancing:RemoveListenerCertificates, elasticloadbalancing:ModifyRule) have Resource: "*" without conditions, enabling unrestricted modifications.

Add Resource Constraints: For statements with unconstrained write actions (around lines 480-493 and 570-575 in original_code), add Condition clauses requiring the elbv2.k8s.aws/cluster tag to match the cluster being managed, following the pattern used in other statements (e.g., lines 455-460).

Apply Tag-Based Filtering: Constrain elasticloadbalancing write operations to only resources tagged with elbv2.k8s.aws/cluster="true" and aws:ResourceTag/elbv2.k8s.aws/cluster="false" to ensure the role only modifies resources it created or is authorized to manage.

Code Pattern

For unconstrained write statements, add:

Condition:
  "Null":
    aws:ResourceTag/elbv2.k8s.aws/cluster: "false"

Apply to: elasticloadbalancing:CreateListener/DeleteListener/CreateRule/DeleteRule block and elasticloadbalancing:SetWebAcl/ModifyListener/AddListenerCertificates/RemoveListenerCertificates/ModifyRule block.

Verification

Run CloudFormation template validation and confirm IAM policy statements with write actions now include resource tag conditions preventing unauthorized modifications to untagged resources.

Priority

high - Estimated effort: 15 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: "*"
- 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: "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*"
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: "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"
Condition:
"Null":
aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
- Effect: Allow
Action:
- elasticloadbalancing:ModifyLoadBalancerAttributes
- elasticloadbalancing:SetIpAddressType
- elasticloadbalancing:SetSecurityGroups
- elasticloadbalancing:SetSubnets
- elasticloadbalancing:DeleteLoadBalancer
Resource: "arn:aws:elasticloadbalancing:*:*:loadbalancer/*"

🤖 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