Skip to main content

Insecure Access Control

Fixing Insecure Access Control

About Insecure Access Control

What is improper access control?

Improper access control is a vulnerability that occurs when a system does not properly restrict or enforce access to resources, such as files, directories, network resources, or application functions.

Examples of improper access control vulnerabilities include:

  • Weak access controls: When access controls are weak or easily bypassed, attackers can gain access to sensitive resources or data by exploiting security weaknesses.
  • Insufficient authorization checks: When authorization checks are insufficient, it can allow unauthorized users to access sensitive data or resources, or to perform actions that they are not authorized to do.
  • Overly permissive access: When access controls are overly permissive, they can allow users to access resources or data that they do not need, increasing the risk of data breaches or other security incidents.

Check out these videos for a high-level explanation:

  • Missing function level access control

  • Missing object level access control

What is the impact of improper access control?

Improper access control can lead to various security threats, such as:

  • Data breaches: Improper access control can allow attackers to access sensitive data, leading to data breaches, data loss, or unauthorized access to confidential information.
  • Unauthorized access to resources: Attackers can exploit improper access control to gain unauthorized access to resources, such as servers, databases, and applications.
  • Account takeover: Attackers can use improper access control to take over user accounts and gain access to sensitive data or resources.

How to prevent improper access control?

Here are some measures that can help ensure proper access control:

  • Strong access controls: Implement strong access controls that restrict access to sensitive resources or data based on user roles and permissions.
  • Proper user authentication and authorization: Implement proper user authentication and authorization mechanisms to ensure that only authorized users can access sensitive data and resources.
  • Input validation and sanitization: Validate and sanitize user input before using it to access internal objects or data. Use regular expressions or input filters to remove or encode any special characters that could be used to access sensitive data or resources.
  • Least privilege: Use the principle of least privilege to restrict access to resources to only what is necessary for each user role. This can help prevent attackers from gaining access to resources that they do not need to access.
  • Regular security audits: Regularly audit your system for security vulnerabilities, including improper access control vulnerabilities. Use automated tools and manual testing to identify potential issues and fix them before they can be exploited.

References

Taxonomies

Explanation & Prevention

Training

Default Security Groups With Unrestricted Traffic

Check if the default security group does not restrict all inbound and outbound traffic. Security Groups set as default must be denied traffic.

Rule-specific references:

Option A: Make sure default Security Groups do not contain any rules

Both SecurityGroupIngress and SecurityGroupEgress Security groups with a GroupName of "default" must not contain any rules.

  1. If a "default" Security Group does container rules and you need those rules, instead create the rules on a non-default Security Group and remove the rules from the "default" Security Group
  2. Test it
  3. Ship it 🚢 and relax 🌴

EC2 Instance Using Default Security Group

EC2 instances should not use default security group(s) (Security Group(s) with a name of "default").

Rule-specific references:

Option A: Remove any Default Security Groups

  1. Remove any default security groups from the configuration
  2. Add non-default security groups if needed
  3. Test it
  4. Ship it 🚢 and relax 🌴

ELB Sensitive Port Is Exposed To Entire Network

The AWS load balancer of the application with a sensitive port connection is exposed to the entire internet.

Rule-specific references:

Option A: Either remove sensitive ports or limit the number of source IP addresses able to traverse a given Security Group Ingress

Make sure that if sensitive ports are open in Properties.SecurityGroupIngress then they should not be open to the entire network (Properties.SecurityGroupIngress.CidrIp ends with /0).

  1. If you locate the following bad patterns:


    AWSTemplateFormatVersion: 2010-09-09
    Resources:
    MyLoadBalancer:
    Type: AWS::ElasticLoadBalancing::LoadBalancer
    Properties:
    AvailabilityZones:
    - "us-east-2a"
    CrossZone: true
    Scheme: internet-facing
    Listeners:
    - InstancePort: '80'
    InstanceProtocol: HTTP
    LoadBalancerPort: '443'
    Protocol: HTTPS
    PolicyNames:
    - My-SSLNegotiation-Policy
    SSLCertificateId: arn:aws:iam::123456789012:server-certificate/my-server-certificate
    HealthCheck:
    Target: HTTP:80/
    HealthyThreshold: '2'
    UnhealthyThreshold: '3'
    Interval: '10'
    Timeout: '5'
    SecurityGroups:
    - !Ref LBSecGroup
    Policies:
    - PolicyName: My-SSLNegotiation-Policy
    PolicyType: SSLNegotiationPolicyType
    Attributes:
    - Name: Reference-Security-Policy
    Value: ELBSecurityPolicy-TLS-1-2-2017-01
    LBSecGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and SSH
    VpcId: my-vpc
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 50
    ToPort: 80
    CidrIp: 127.0.0.1/0
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 127.0.0.1/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
  2. Replace it with something similar to the following:

    AWSTemplateFormatVersion: 2010-09-09
    Resources:
    MyLoadBalancer:
    Type: AWS::ElasticLoadBalancing::LoadBalancer
    Properties:
    AvailabilityZones:
    - "us-east-2a"
    CrossZone: true
    Scheme: internet-facing
    Listeners:
    - InstancePort: '80'
    InstanceProtocol: HTTP
    LoadBalancerPort: '443'
    Protocol: HTTPS
    PolicyNames:
    - My-SSLNegotiation-Policy
    SSLCertificateId: arn:aws:iam::123456789012:server-certificate/my-server-certificate
    HealthCheck:
    Target: HTTP:80/
    HealthyThreshold: '2'
    UnhealthyThreshold: '3'
    Interval: '10'
    Timeout: '5'
    SecurityGroups:
    [ !Ref LBNegativeSecGroup01 ]
    Policies:
    - PolicyName: My-SSLNegotiation-Policy
    PolicyType: SSLNegotiationPolicyType
    Attributes:
    - Name: Reference-Security-Policy
    Value: ELBSecurityPolicy-TLS-1-2-2017-01
    LBNegativeSecGroup01:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and SSH
    VpcId: my-vpc
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 50
    ToPort: 80
    CidrIp: 127.0.0.1/32
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 127.0.0.1/32
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
  3. If you locate the following bad patterns:

    AWSTemplateFormatVersion: 2010-09-09
    Parameters:
    MySubnets:
    Description: "My subnet"
    Type: List<String>
    Resources:
    ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
    Name: ip-target-alb
    Subnets: !Ref MySubnets
    SecurityGroups:
    - !Ref ALBSecGroup
    Tags:
    - Key: Name
    Value: ip-target-alb
    ALBSecGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and SSH
    VpcId: my-vpc
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 127.0.0.1/32
    - IpProtocol: tcp
    FromPort: 6379
    ToPort: 6379
    CidrIp: 127.0.0.1/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    HTTPALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
    LoadBalancerArn: !Ref ApplicationLoadBalancer
    Port: 80
    Protocol: HTTP
    DefaultActions:
    - Type: forward
    TargetGroupArn: !Ref IPTargetGroup
    IPTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
    VpcId: my-vpc
    Port: 80
    Protocol: HTTP
    TargetType: ip
    Matcher:
    HttpCode: '200'
    HealthCheckIntervalSeconds: 10
    HealthCheckPath: /health/check
    HealthCheckProtocol: HTTP
    HealthCheckTimeoutSeconds: 5
    HealthyThresholdCount: 2
    UnhealthyThresholdCount: 2
    TestListenerRule1:
    Type: "AWS::ElasticLoadBalancingV2::ListenerRule"
    Properties:
    Priority: 1
    ListenerArn: !Ref HTTPALBListener
    Conditions:
    - Field: "host-header"
    Values:
    - "test1.checkmarx.com"
    Actions:
    - Type: "forward"
    TargetGroupArn: !Ref IPTargetGroup
    Order: 1
    ForwardConfig:
    TargetGroups:
    - TargetGroupArn: !Ref IPTargetGroup
    Weight: 1
    TargetGroupStickinessConfig:
    Enabled: false
  4. Replace it with something similar to the following:

    AWSTemplateFormatVersion: 2010-09-09
    Parameters:
    MySubnets:
    Description: "My subnet"
    Type: List<String>
    Resources:
    ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
    Name: ip-target-alb
    Subnets: !Ref MySubnets
    SecurityGroups:
    - !Ref ALBNegativeSecGroup
    Tags:
    - Key: Name
    Value: ip-target-alb
    ALBNegativeSecGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and SSH
    VpcId: my-vpc
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 127.0.0.1/32
    - IpProtocol: tcp
    FromPort: 77
    ToPort: 77
    CidrIp: 127.0.0.1/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    HTTPALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
    LoadBalancerArn: !Ref ApplicationLoadBalancer
    Port: 80
    Protocol: HTTP
    DefaultActions:
    - Type: forward
    TargetGroupArn: !Ref IPTargetGroup
    IPTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
    VpcId: my-vpc
    Port: 80
    Protocol: HTTP
    TargetType: ip
    Matcher:
    HttpCode: '200'
    HealthCheckIntervalSeconds: 10
    HealthCheckPath: /health/check
    HealthCheckProtocol: HTTP
    HealthCheckTimeoutSeconds: 5
    HealthyThresholdCount: 2
    UnhealthyThresholdCount: 2
    TestListenerRule1:
    Type: "AWS::ElasticLoadBalancingV2::ListenerRule"
    Properties:
    Priority: 1
    ListenerArn: !Ref HTTPALBListener
    Conditions:
    - Field: "host-header"
    Values:
    - "test1.checkmarx.com"
    Actions:
    - Type: "forward"
    TargetGroupArn: !Ref IPTargetGroup
    Order: 1
    ForwardConfig:
    TargetGroups:
    - TargetGroupArn: !Ref IPTargetGroup
    Weight: 1
    TargetGroupStickinessConfig:
    Enabled: false
  5. If you locate the following bad patterns:

    AWSTemplateFormatVersion: 2010-09-09
    Parameters:
    MySubnet:
    Description: "My subnet"
    Type: List<String>
    Resources:
    GatewayLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
    Name: my-gateway-load-balancer
    Scheme: internet-facing
    Subnets: !Ref MySubnet
    InstancesSecGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and SSH
    VpcId: my-vpc
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 127.0.0.1/32
    - IpProtocol: tcp
    FromPort: 636
    ToPort: 636
    CidrIp: 127.0.0.1/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    EC2Instance01:
    Type: AWS::EC2::Instance
    Properties:
    InstanceType: t3.2xlarge
    SecurityGroups:
    - !Ref 'InstancesSecGroup'
    KeyName: my-rsa-key
    ImageId: ami-79fd7eee
    EC2Instance02:
    Type: AWS::EC2::Instance
    Properties:
    InstanceType: t3.2xlarge
    SecurityGroups:
    - !Ref 'InstancesSecGroup'
    KeyName: my-rsa-key
    ImageId: ami-79fd7eee
    GatewayLoadBalancerTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
    Name: t10-networklb-target
    Port: 443
    Protocol: TCP
    VpcId: t10-vpc-id
    TargetGroupAttributes:
    - Key: deregistration_delay.timeout_seconds
    Value: 60
    Targets:
    - Id: !Ref EC2Instance01
    Port: 443
    - Id: !Ref EC2Instance02
    Port: 443
    Tags:
    - Key: Name
    Value: t10-networklb-target
    GatewayLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
    DefaultActions:
    - Type: forward
    TargetGroupArn: !Ref GatewayLoadBalancerTargetGroup
    LoadBalancerArn: !Ref GatewayLoadBalancer
    Port: 443
    Protocol: TCP
    GatewayLoadBalancerListenerCert:
    Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
    Properties:
    Certificates:
    - CertificateArn: arn:aws:acm:eu-west-1:xxxaccountxxx:certificate/123456....
    ListenerArn: !Ref GatewayLoadBalancerListener
  6. Replace it with something similar to the following:

    AWSTemplateFormatVersion: 2010-09-09
    Parameters:
    MySubnet:
    Description: "My subnet"
    Type: List<String>
    Resources:
    NetworkLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
    Name: t10-networkloadbalancer
    Scheme: internet-facing
    Subnets: !Ref MySubnet
    Type: network
    Tags:
    - Key: Name
    Value: t10-networklb
    InstancesNegativeSecGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and SSH
    VpcId: my-vpc
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 127.0.0.1/32
    - IpProtocol: tcp
    FromPort: 77
    ToPort: 77
    CidrIp: 127.0.0.1/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    EC2Instance01:
    Type: AWS::EC2::Instance
    Properties:
    InstanceType: t3.2xlarge
    SecurityGroups: [!Ref 'InstancesNegativeSecGroup']
    KeyName: my-rsa-key
    ImageId: ami-79fd7eee
    EC2Instance02:
    Type: AWS::EC2::Instance
    Properties:
    InstanceType: t3.2xlarge
    SecurityGroups: [!Ref 'InstancesNegativeSecGroup']
    KeyName: my-rsa-key
    ImageId: ami-79fd7eee
    NetworkLoadBalancerTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
    Name: t10-networklb-target
    Port: 443
    Protocol: TCP
    VpcId: t10-vpc-id
    TargetGroupAttributes:
    - Key: deregistration_delay.timeout_seconds
    Value: 60
    Targets:
    - Id: !Ref EC2Instance01
    Port: 443
    - Id: !Ref EC2Instance02
    Port: 443
    Tags:
    - Key: Name
    Value: t10-networklb-target
    NetworkLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
    DefaultActions:
    - Type: forward
    TargetGroupArn: !Ref NetworkLoadBalancerTargetGroup
    LoadBalancerArn: !Ref NetworkLoadBalancer
    Port: 443
    Protocol: TCP
    NetworkLoadBalancerListenerCert:
    Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
    Properties:
    Certificates:
    - CertificateArn: arn:aws:acm:eu-west-1:xxxaccountxxx:certificate/123456....
    ListenerArn: !Ref NetworkLoadBalancerListener
  7. Test it

  8. Ship it 🚢 and relax 🌴

IAM Policies With Full Privileges

IAM policies should not allow full administrative privileges (for all resources).

Rule-specific references:

Option A: Remove the All Specifier from the Resource and Action Statements of the Policy

Policies should not contain Statements with Actions and Resources that Allow all ("*").

  1. Remove the value "*" from any Action and Resource and replace it with only the number of actions and resources needed
  2. Test it
  3. Ship it 🚢 and relax 🌴

IAM Policy Grants AssumeRole Permission Across All Services

Check if any IAM Policy grants AssumeRole permission across all services.

Rule-specific references:

Option A: Replace the Resource's All Specifier with a more focussed Resource and Replace the Action with more specific Action(s)

A policy (AWS::IAM::Policy) should not have a Statement with Effect: "Allow" and an Action of "sts:AssumeRole" with a Resource property that specifies all ("*"). Similar to the following example:

{
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "mygrouppolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Resource": "*"
}
]
},
...
}
}
  1. Remove the value "*" from the Resource or replace it with as few services as possible (ideally one)

  2. Replace "sts:AssumeRole" with discreet Actions

    {
    "Type": "AWS::IAM::Policy",
    "Properties": {
    "PolicyName": "mygrouppolicy",
    "PolicyDocument": {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": [
    "s3:GetObject",
    "s3:PutObject",
    "s3:PutObjectAcl"
    ],
    "Resource": "arn:aws:s3:::myAWSBucket/*"
    }
    ]
    },
    ...
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

IAM Policy Grants Full Permissions

Check if an IAM policy is granting full permissions to resources from the get-go, instead of granting permissions gradually as necessary.

Rule-specific references:

Option A: Remove the All Specifier from the Action and make sure the Resource does not allow All or Admin

A policy (AWS::IAM::Policy) should not have a Statement with Effect: "Allow" and an Action of all ("*") with a Resource property that specifies all ("*") or "arn:aws:iam::aws:policy/AdministratorAccess".

  1. Remove the value "*" from any Action that has a sibling Resource property that specifies all ("*") or "arn:aws:iam::aws:policy/AdministratorAccess"
  2. Test it
  3. Ship it 🚢 and relax 🌴

S3 Bucket ACL Allows Read Or Write to All Users

S3 Buckets should not be readable and writable to all users.

Rule-specific references:

Option A: An S3 Bucket Should Not Have Access Control of Public Read Write

A bucket (AWS::S3::Bucket) should not have an AccessControl of "PublicReadWrite"

  1. Replace any S3 Bucket AccessControl values of "PublicReadWrite" with a more restrictive value
  2. Test it
  3. Ship it 🚢 and relax 🌴

S3 Bucket ACL Allows Read to Any Authenticated User

S3 Buckets should not be readable to all authenticated users.

Rule-specific references:

Option A: An S3 Bucket Should Not Have an Access Control of Authenticated Read.

A bucket (AWS::S3::Bucket) should not have an AccessControl of AuthenticatedRead

  1. Remove or replace the value "AuthenticatedRead" from any S3 Bucket AccessControl with a more restrictive value
  2. Test it
  3. Ship it 🚢 and relax 🌴

Rule-specific references:

S3 Bucket Access to Any Principal

The S3 Bucket should not have the (PublicAccessBlockConfiguration empty or PublicAccessBlockConfiguration.IgnorePublicAcls = false or PublicAccessBlockConfiguration.RestrictPublicBuckets = false ) and ( policy.Statement contain [Effect="Allow" and (Principal="*" or Principal.AWS="*")]).

Option A: Reconfigure the S3 Bucket

  1. Consider changing the defective configuration with the more secure configuration as outlined in the examples below:

    Defective:

    Resources:
    Bucket:
    Type: AWS::S3::Bucket
    Properties:
    PublicAccessBlockConfiguration:
    BlockPublicAcls: false
    BlockPublicPolicy: false
    IgnorePublicAcls: true
    RestrictPublicBuckets: false
    BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
    Bucket: !Ref Bucket
    PolicyDocument:
    Statement:
    - Effect: Allow
    Principal:
    AWS:
    - "*"
    Action: s3:GetObject
    Resource: arn:aws:s3:::DOC-EXAMPLE-BUCKET/*
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
    Bucket2:
    Type: AWS::S3::Bucket
    Properties:
    PublicAccessBlockConfiguration:
    BlockPublicAcls: false
    BlockPublicPolicy: false
    IgnorePublicAcls: false
    RestrictPublicBuckets: true
    BucketPolicy2:
    Type: AWS::S3::BucketPolicy
    Properties:
    Bucket: !Ref Bucket2
    PolicyDocument:
    Statement:
    - Effect: Allow
    Principal:
    AWS:
    - "*"
    Action: s3:GetObject
    Resource: arn:aws:s3:::DOC-EXAMPLE-BUCKET/*
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'

    Not Defective:

    Resources:
    Bucket:
    Type: AWS::S3::Bucket
    Properties:
    PublicAccessBlockConfiguration:
    BlockPublicAcls: false
    BlockPublicPolicy: false
    IgnorePublicAcls: true
    RestrictPublicBuckets: true
    BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
    Bucket: !Ref Bucket
    PolicyDocument:
    Statement:
    - Effect: Allow
    Principal:
    AWS:
    - arn:aws:iam::111122223333:user/Alice
    - arn:aws:iam::111122223333:user/Fabio
    Action: s3:GetObject
    Resource: arn:aws:s3:::DOC-EXAMPLE-BUCKET/*
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. Test it

  3. Ship it 🚢 and relax 🌴

S3 Bucket Allows Put Action From All Principals

S3 Buckets must not allow Put Actions From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the 'Effect' must not be 'Allow' when the 'Action' is Put, for all Principals.

Rule-specific references:

Option A: Constrain Resource and/or Principal values to something more granular

Where a Put action is present the Resource and/or Principal should not be All ("*").

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy1:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:PutObject"
    - "s3:GetObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. Change the value of the Resource and/or Principal to more granular values

  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Set Effect to Deny where a Principal specifies All

Where a Principal specifies All ("*"), the Effect should be to Deny.

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy3:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:PutObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. And modify it to:

    Resources:
    SampleBucketPolicy4:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:PutObject"
    Effect: Deny
    Resource: '*'
    Principal: '*'
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows Delete Action From All Principals

S3 Buckets must not allow Delete Actions From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the 'Effect' must not be 'Allow' when the 'Action' is Delete, for all Principals.

Rule-specific references:

Option A: Constrain Resource and/or Principal values to something more granular

Where a Delete action is present the Resource and/or Principal should not be All ("*").

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy1:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:DeleteObject"
    - "s3:GetObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. Change the value of the Resource and/or Principal to more granular values

  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Set Effect to Deny where a Principal specifies All

Where a Principal specifies All ("*"), the Effect should be to Deny.

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy3:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:DeleteObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. And modify it to:

    Resources:
    SampleBucketPolicy4:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:DeleteObject"
    Effect: Deny
    Resource: '*'
    Principal: '*'
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows Get Action From All Principals

S3 Buckets must not allow Get Actions From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the 'Effect' must not be 'Allow' when the 'Action' is Get, for all Principals.

Rule-specific references:

Option A: Constrain Resource and/or Principal values to something more granular

Where a Get action is present the Resource and/or Principal should not be All ("*").

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy1:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:DeleteObject"
    - "s3:GetObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. Change the value of the Resource and/or Principal to more granular values

  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Set Effect to Deny where a Principal specifies All

Where a Principal specifies All ("*"), the Effect should be to Deny.

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy3:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:GetObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. And modify it to:

    Resources:
    SampleBucketPolicy4:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:GetObject"
    Effect: Deny
    Resource: '*'
    Principal: '*'
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Allows List Action From All Principals

S3 Buckets must not allow List Actions From All Principals, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the 'Effect' must not be 'Allow' when the 'Action' is 'List', for all Principals.

Rule-specific references:

Option A: Constrain Resource and/or Principal values to something more granular

Where a List action is present the Resource and/or Principal should not be All ("*").

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy1:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:ListObject"
    - "s3:GetObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. Change the value of the Resource and/or Principal to more granular values

  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Set Effect to Deny where a Principal specifies All

Where a Principal specifies All ("*"), the Effect should be to Deny.

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy3:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:ListObject"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. And modify it to:

    Resources:
    SampleBucketPolicy4:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:ListObject"
    Effect: Deny
    Resource: '*'
    Principal: '*'
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket With All Permissions

S3 Buckets must not have all permissions, as to prevent leaking private information to the entire internet or allow unauthorized data tampering/deletion. This means the 'Effect' must not be 'Allow' when the 'Action' is '*', for all Principals.

Rule-specific references:

Option A: Constrain Resource and/or Principal values to something more granular

Where all ("*") Actions are allowed the Resource and Principal should not be All ("*").

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy1:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action: "*"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. Change the value of the Resource and Principal to more granular values

  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Set Effect to Deny where a Principal specifies All

Where a Principle specifies All ("*"), the Effect should be to Deny.

  1. Locate the following pattern:

    Resources:
    SampleBucketPolicy3:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action: "*"
    Effect: Allow
    Resource: "*"
    Principal: "*"
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  2. And modify it to:

    Resources:
    SampleBucketPolicy4:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
    Bucket: !Ref DOC-EXAMPLE-BUCKET
    PolicyDocument:
    Statement:
    - Action:
    - "s3:ListObject"
    Effect: Deny
    Resource: '*'
    Principal: '*'
    Condition:
    StringLike:
    'aws:Referer':
    - 'http://www.example.com/*'
    - 'http://example.net/*'
  3. Test it

  4. Ship it 🚢 and relax 🌴

Security Group With Unrestricted Access To SSH

SSH (TCP:22) should not be exposed to the world in AWS Security Group. There is very rarely a need for ranges of IP addresses to be able to access SSH port 22.

Rule-specific references:

Option A: Only specify single IP addresses or a very small range that can access SSH port 22

All SecurityGroupIngress blocks of any given AWS::EC2::SecurityGroup should not have port 22 open to the world.

  1. Locate one of the following vulnerable patterns:

    Resources:
    Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
    SecurityGroups:
    - !Ref InstanceSecurityGroup
    KeyName: mykey
    ImageId: ''
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
  2. Modify the config to something like the following:

    Resources:
    Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
    SecurityGroups:
    - !Ref InstanceSecurityGroup
    KeyName: mykey
    ImageId: ''
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 203.0.113.1/32
  3. Test it

  4. Ship it 🚢 and relax 🌴

Security Group Ingress With All Protocols

AWS Security Group Ingress should not specify all protocols to prevent allowing traffic on all ports.

Rule-specific references:

Option A: Set the value of the IP Protocol to a single specific protocol

Change all occurrences of SecurityGroupIngress[n].IpProtocol and Properties.IpProtocol with value -1 to one of the accepted specific protocols.

  1. Locate the following pattern:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: -1
    FromPort: 80
    ToPort: 80
    CidrIp: 0.0.0.0/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 0.0.0.0/0
    OutboundRule:
    Type: AWS::EC2::SecurityGroupEgress
    Properties:
    IpProtocol: tcp
    FromPort: 0
    ToPort: 65535
    DestinationSecurityGroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    InboundRule:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
    IpProtocol: -1
    FromPort: 0
    ToPort: 65535
    SourceSecurityGroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
  2. Modify it to something like the following:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 0.0.0.0/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 0.0.0.0/0
    OutboundRule:
    Type: AWS::EC2::SecurityGroupEgress
    Properties:
    IpProtocol: tcp
    FromPort: 0
    ToPort: 65535
    DestinationSecurityGroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    InboundRule:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
    IpProtocol: tcp
    FromPort: 0
    ToPort: 65535
    SourceSecurityGroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
  3. Test it

  4. Ship it 🚢 and relax 🌴

Security Group Unrestricted Access To RDP

AWS EC2 Security Groups should not allow 0.0.0.0/0 for RDP (port:3389).

Rule-specific references:

Option A: Do not allow RDP ports to be open in a Security Group

Spoofing IP addresses is a possible attack, and RDP has had many known vulnerabilities, so just restricting the number of IP addresses that can access the RDP ports is probably not your best option. By far the best option is to not allow RDP ports to be open. If you must use RDP use it inside a VPN or SSH tunnel. Also, by restricting the number of IP addresses that are allowed access to any given port you are helping to restrict any blast radius.

  1. Locate the following pattern:

    Resources:
    Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
    SecurityGroups:
    - !Ref InstanceSecurityGroup
    KeyName: mykey
    ImageId: ''
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 3389
    ToPort: 3389
    CidrIp: 0.0.0.0/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 0.0.0.0/0
  2. Modify it to something like the following:

    Resources:
    Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
    SecurityGroups:
    - !Ref InstanceSecurityGroup
    KeyName: mykey
    ImageId: ''
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 127.0.0.1/32
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 127.0.0.1/33
  3. Test it

  4. Ship it 🚢 and relax 🌴

Security Groups Allows Unrestricted Outbound Traffic

No security group should allow unrestricted egress access.

Rule-specific references:

Option A: Set the value of the IP Protocol to a single specific protocol

Change all occurrences of Properties.SecurityGroupEgress[n].IpProtocol with value "ALL" to one of the accepted specific protocols.

  1. Locate the following pattern:

    Parameters:
    KeyName:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: 'AWS::EC2::KeyPair::KeyName'
    Resources:
    Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
    SecurityGroups:
    - !Ref InstanceSecurityGroup
    - MyExistingSecurityGroup
    KeyName: !Ref KeyName
    ImageId: ami-7a11e213
    InstanceSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
    GroupDescription: Enable SSH access via port 22
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: '22'
    ToPort: '22'
    CidrIp: 0.0.0.0/0
    SecurityGroupEgress:
    - IpProtocol: ALL
    FromPort: '22'
    ToPort: '22'
    CidrIp: 0.0.0.0/0
  2. Modify it to something like the following:

    Parameters:
    KeyName:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: 'AWS::EC2::KeyPair::KeyName'
    Resources:
    Ec2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
    SecurityGroups:
    - !Ref InstanceSecurityGroup
    - MyExistingSecurityGroup
    KeyName: !Ref KeyName
    ImageId: ami-7a11e213
    InstanceSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
    GroupDescription: Enable SSH access via port 22
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: '22'
    ToPort: '22'
    CidrIp: 0.0.0.0/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: '22'
    ToPort: '22'
    CidrIp: 0.0.0.0/0
  3. Test it

  4. Ship it 🚢 and relax 🌴

Unrestricted Security Group Ingress

AWS Security Group Ingress CIDR should ideally not be open to the world.

Rule-specific references:

Option A: Limit the Source IP addresses that can access VPC targets

Ideally, limit the number of Source IP addresses that can send data that is allowed through a given port.

  1. Locate the following pattern:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    Description: TCP
    FromPort: 80
    ToPort: 80
    CidrIp: 0.0.0.0/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    Description: TCP
    FromPort: 80
    ToPort: 80
    CidrIp: 0.0.0.0/0
    OutboundRule:
    Type: AWS::EC2::SecurityGroupEgress
    Properties:
    Description: TCP
    IpProtocol: tcp
    FromPort: 0
    ToPort: 65535
    CidrIp: 0.0.0.0/0
    DestinationSecurityGroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    InboundRule:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
    Description: TCP
    IpProtocol: tcp
    FromPort: 0
    ToPort: 65535
    CidrIpv6: ::/0
    SourceSecurityGroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
  2. Modify it to something like the following:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    Description: TCP
    FromPort: 80
    ToPort: 80
    CidrIp: 192.0.2.0/24
    SecurityGroupEgress:
    - IpProtocol: tcp
    Description: TCP
    FromPort: 80
    ToPort: 80
    CidrIp: 192.0.2.0/24
    OutboundRule:
    Type: AWS::EC2::SecurityGroupEgress
    Properties:
    Description: TCP
    IpProtocol: tcp
    FromPort: 0
    ToPort: 0
    CidrIp: 192.0.2.0/24
    DestinationSecurityGroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    InboundRule:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
    Description: TCP
    IpProtocol: tcp
    FromPort: 0
    ToPort: 0
    CidrIpv6: 2001:0DB8:1234::/48
    SourceSecurityGroupId:
    Fn::GetAtt:
    - SourceSG
    - GroupId
    GroupId:
    Fn::GetAtt:
    - TargetSG
    - GroupId
  3. Test it

  4. Ship it 🚢 and relax 🌴

EC2 Sensitive Port Is Publicly Exposed

The AWS EC2 instance has a sensitive port connection exposed to the entire network.

Rule-specific references:

Option A: Limit the number of source IP addresses able to traverse inbound ports

CidrIp should not end with \0 (allowing all sources). Instead limit the CidrIp to as few source IP addresses as possible, ideally with a trailing \32. Ideally, the IpProtocol should not be -1 (all) but be something more specific.

  1. Locate the following bad patterns:

    Pattern one:

    AWSTemplateFormatVersion: 2010-09-09T00:00:00Z
    Resources:
    UnsafeSecGroup01:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and redis
    VpcId: my-vpc
    SecurityGroupIngress:
    - FromPort: 8080
    ToPort: 8080
    CidrIp: 127.0.0.1/32
    IpProtocol: tcp
    - IpProtocol: tcp
    FromPort: 6379
    ToPort: 6379
    CidrIp: 10.0.0.1/0
    SecurityGroupEgress:
    - FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    IpProtocol: tcp
    EC2Instance01:
    Type: AWS::EC2::Instance
    Properties:
    ImageId: ami-79fd7eee
    InstanceType: t3.medium
    SecurityGroups:
    - UnsafeSecGroup01
    KeyName: my-new-rsa-key

    Pattern two:

    AWSTemplateFormatVersion: 2010-09-09T00:00:00Z
    Resources:
    UnsafeSecGroup02:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow HTTP and mysql
    VpcId: my-vpc
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 80
    ToPort: 80
    CidrIp: 127.0.0.1/32
    - ToPort: 1434
    CidrIp: 10.0.0.1/0
    IpProtocol: tcp
    FromPort: 1433
    - IpProtocol: tcp
    FromPort: 150
    ToPort: 180
    CidrIp: 10.0.0.1/0
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    EC2Instance02:
    Type: AWS::EC2::Instance
    Properties:
    InstanceType: t3.medium
    SecurityGroups:
    - UnsafeSecGroup02
    KeyName: my-new-rsa-key
    ImageId: ami-79fd7eee

    Pattern three:

    AWSTemplateFormatVersion: 2010-09-09T00:00:00Z
    Resources:
    UnsafeSecGroup03:
    Type: AWS::EC2::SecurityGroup
    Properties:
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    GroupDescription: Allow HTTP and hadoop
    VpcId: my-vpc
    SecurityGroupIngress:
    - ToPort: 80
    CidrIp: 0.0.0.0/0
    IpProtocol: tcp
    FromPort: 80
    - ToPort: 9000
    CidrIp: 10.0.0.1/0
    IpProtocol: tcp
    FromPort: 9000
    EC2Instance03:
    Type: AWS::EC2::Instance
    Properties:
    SecurityGroups:
    - UnsafeSecGroup03
    KeyName: my-new-rsa-key
    ImageId: ami-79fd7eee
    InstanceType: t3.medium

    Pattern four:

    AWSTemplateFormatVersion: 2010-09-09T00:00:00Z
    Resources:
    UnsafeSecGroup04:
    Type: AWS::EC2::SecurityGroup
    Properties:
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 0.0.0.0/0
    GroupDescription: Allow LDAP and SNMP
    VpcId: my-vpc
    SecurityGroupIngress:
    - ToPort: 389
    FromPort: 389
    IpProtocol: all
    CidrIp: 10.0.0.0/0
    - ToPort: 150
    FromPort: 180
    IpProtocol: udp
    CidrIp: 10.0.0.1/0
    - ToPort: 53
    FromPort: 53
    IpProtocol: "-1"
    CidrIp: 10.0.0.1/0
    EC2Instance03:
    Type: AWS::EC2::Instance
    Properties:
    SecurityGroups:
    - UnsafeSecGroup04
    KeyName: my-new-rsa-key
    ImageId: ami-79fd7eee
    InstanceType: t3.medium
  2. Modify the Security Group(s) to something like the following:

    AWSTemplateFormatVersion: 2010-09-09T00:00:00Z
    Resources:
    SafeSecGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    SecurityGroupEgress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 127.0.0.1/32
    GroupDescription: Allow HTTP and SSH
    VpcId: my-vpc
    SecurityGroupIngress:
    - FromPort: 80
    ToPort: 80
    CidrIp: 127.0.0.1/32
    IpProtocol: tcp
    - ToPort: 77
    CidrIp: 127.0.0.1/32
    IpProtocol: all
    FromPort: 77
    MyNegativeEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
    SecurityGroups:
    - SafeSecGroup
    KeyName: my-new-rsa-key
    ImageId: ami-79fd7eee
    InstanceType: t3.medium
  3. Test it

  4. Ship it 🚢 and relax 🌴

Remote Desktop Port Open

The Remote Desktop port (3389) is open to the world in an AWS EC2 Security Group. If you need to provide Remote Desktop communications to an EC2 instance, do so via a VPN or SSH tunnel.

Rule-specific references:

Option A: Close the Remote Desktop ingress port (3389)

The recommended option is to remove the RDP port and use either a VPN or SSH tunnel in which any RDP traffic or other traffic can pass encrypted.

  1. Locate the following pattern:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow rdp to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 3389
    ToPort: 3389
    CidrIp: 0.0.0.0/0
  2. Modify the config to something like the following:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow rdp to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 22
    ToPort: 22
    CidrIp: 203.0.113.1/32
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Limit the Remote Desktop ingress port (3389) to a single or very small set of IP addresses

Although this option satisfies the security rule, it's still not a great option. RDP has a long history of vulnerabilities and is usually best to be encrypted inside a VPN or SSH tunnel. However: If you still want to pass RDP traffic over a network then follow these steps:

  1. Locate the following pattern:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow rdp to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 3389
    ToPort: 3389
    CidrIp: 0.0.0.0/0
  2. Modify the config to something like the following:

    Resources:
    InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
    GroupDescription: Allow rdp to client host
    VpcId:
    Ref: myVPC
    SecurityGroupIngress:
    - IpProtocol: tcp
    FromPort: 3389
    ToPort: 3389
    CidrIp: 203.0.113.1/32
  3. Test it

  4. Ship it 🚢 and relax 🌴