Skip to main content

Insecure Network Communication

Fixing Cleartext Transmission

About Cleartext Transmission

What is Cleartext Transmission?

Cleartext transmission, also known as plaintext transmission, refers to the process of transmitting data over a network or communication channel without encryption or other security measures that protect the data from interception or unauthorized access.

In cleartext transmission, the data is transmitted in plain, human-readable format, which means that anyone who has access to the communication channel can read, intercept, or modify the data without any difficulty.

Cleartext transmission can occur in various communication protocols, such as HTTP, FTP, SMTP, and Telnet, and can affect various types of data, such as login credentials, credit card information, personal data, and other types of sensitive information.

Check out these videos for a high-level explanation:

  • Communication over cleartext protocol

  • Unprotected transport of sensitive information

  • Unprotected transport of credentials

What is the impact of Cleartext Transmission?

Cleartext transmission can lead to various security threats and risks, such as:

  • Information disclosure: Cleartext transmission can expose sensitive or confidential information to unauthorized parties, such as passwords, credit card numbers, personal data, or other types of sensitive information.
  • Man-in-the-middle attacks: Cleartext transmission can be intercepted by attackers who can eavesdrop on the communication channel, modify or steal the data, or impersonate the parties involved in the communication.
  • Identity theft: Cleartext transmission can lead to identity theft, where attackers can use stolen personal data to assume the identity of victims and perform various malicious activities, such as financial fraud or unauthorized access to systems.
  • Data tampering: Cleartext transmission can allow attackers to modify or inject false data into the communication channel, leading to data tampering, data corruption, or other types of malicious activities.

How to prevent Cleartext Transmission?

To prevent cleartext transmission, you can take the following steps:

  • Use encryption: Encrypt sensitive data before transmitting it over any communication channel. Use encryption protocols such as SSL/TLS or HTTPS to ensure that data is encrypted in transit.
  • Secure communication channels: Use secure communication channels such as SFTP, SSH, or VPNs to transmit sensitive data. These protocols provide encryption and authentication, which can help prevent unauthorized access and eavesdropping.
  • Disable cleartext protocols: Disable cleartext protocols such as HTTP or FTP, and use only encrypted protocols such as HTTPS or SFTP to transmit sensitive data.
  • Implement data validation: Implement data validation mechanisms to ensure that only valid data is transmitted. Validate user input and filter out any sensitive data before transmitting it.

References

Taxonomies

Training

Unencrypted MSK Broker

AWS offers a Managed Streaming for Kafka cluster service, which may transmit data in cleartext.

More information can be found here:

Option A: Ensure MSK Encryption in Transit

  1. Go through the issues that GuardRails identified

  2. Locate the aws_msk_cluster resource

    resource "aws_msk_cluster" "example" {
    cluster_name = "example"
    kafka_version = "2.4.1"
    number_of_broker_nodes = 3

    broker_node_group_info {
    instance_type = "kafka.m5.large"
    ebs_volume_size = 1000
    client_subnets = [
    aws_subnet.subnet_az1.id,
    aws_subnet.subnet_az2.id,
    aws_subnet.subnet_az3.id,
    ]
    security_groups = [aws_security_group.sg.id]
    }
    }
  3. Ensure that the aws_msk_cluster resource includes an encryption_info object, for example like shown below

    resource "aws_msk_cluster" "example" {
    cluster_name = "example"
    ...
    encryption_info {
    encryption_at_rest_kms_key_arn = aws_kms_key.kms.arn
    }
    }

Unencrypted Kinesis Stream

AWS offers a Kinesis Stream resource, which is a managed service that scales elastically for real-time processing of streaming big data. This service may transmit data in cleartext.

Rule-specific references:

Option A: Ensure Kinesis Stream Encryption in Transit

  1. Go through the issues that GuardRails identified

  2. Locate the aws_kinesis_stream resource

    resource "aws_kinesis_stream" "test_stream" {
    name = "terraform-kinesis-test"
    shard_count = 1
    retention_period = 48

    shard_level_metrics = [
    "IncomingBytes",
    "OutgoingBytes",
    ]

    tags = {
    Environment = "test"
    }
    }
  3. Ensure that the aws_kinesis_stream resource includes the encryption_type argument set to KMS

    resource "aws_kinesis_stream" "test_stream" {
    name = "terraform-kinesis-test"
    shard_count = 1
    retention_period = 48
    encryption_type = "KMS"
    ...
    }

Ensure Encryption in Transit

Certain services communicate via HTTP unless configured otherwise.

Option A: Ensure AWS Load Balancer is using HTTPS

  1. Go through the issues that GuardRails identified

  2. Locate the aws_lb_listener resource

    resource "aws_lb_listener" "front_end" {
    load_balancer_arn = aws_lb.front_end.arn
    port = "80"
    protocol = "HTTP"
    ssl_policy = "ELBSecurityPolicy-2016-08"
    certificate_arn = "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4"

    default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.front_end.arn
    }
    }
  3. Update the protocol to either HTTPS or TLS

Option B: Ensure CloudFront is using HTTPS

  1. Go through the issues that GuardRails identified

  2. Locate the aws_cloudfront_distribution resource

    resource "aws_cloudfront_distribution" "s3_distribution" {
    origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    ...
    }

    enabled = true
    ...

    aliases = ["mysite.example.com", "yoursite.example.com"]

    default_cache_behavior {
    allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = local.s3_origin_id

    forwarded_values {
    query_string = false

    cookies {
    forward = "none"
    }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl = 0
    default_ttl = 3600
    max_ttl = 86400
    }
  3. If the viewer_protocol_policy is missing or set to allow-all, then change it to either https-only or redirect-to-https

ALB Listening on HTTP

AWS Application Load Balancer (alb) should not listen on HTTP.

Rule-specific references:

Option A: Make sure no Application Load Balancer Listeners are listening on HTTP

All traffic to and from Application Load Balancers should be TLS encrypted.

  • Change any occurrences of resource aws_lb_listener default_action.redirect.protocol value being "HTTP" to "HTTPS"
  • Make sure resource aws_lb_listener protocol is defined and has its value set to "HTTPS" for other types
  1. Locate the following vulnerable patterns:

    Vulnerable default_action of type "redirect" pattern:

    resource "aws_lb_listener" "listener" {
    load_balancer_arn = aws_lb.test.arn
    port = 80
    default_action {
    type = "redirect"

    redirect {
    port = "80"
    protocol = "HTTP"
    status_code = "HTTP_301"
    }
    }
    }

    resource "aws_lb" "test" {
    name = "test123"
    load_balancer_type = "application"
    subnets = [aws_subnet.subnet1.id, aws_subnet.subnet2.id]
    internal = true
    }

    Vulnerable default_action of other types pattern:

    resource "aws_lb_listener" "listener" {
    load_balancer_arn = aws_lb.test.arn
    port = 80
    default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.test.arn
    }
    }
  2. Modify the config to something like the following:

    Replacement default_action of type "redirect" pattern:

    resource "aws_lb_listener" "listener" {
    load_balancer_arn = aws_lb.test.arn
    port = 80
    default_action {
    type = "redirect"

    redirect {
    port = "80"
    protocol = "HTTPS"
    status_code = "HTTPS_301"
    }
    }
    }

    resource "aws_lb" "test" {
    name = "test123"
    load_balancer_type = "application"
    subnets = [aws_subnet.subnet1.id, aws_subnet.subnet2.id]
    internal = true
    }

    Replacement default_action of other types pattern:

    resource "aws_lb_listener" "listener" {
    load_balancer_arn = aws_lb.test.arn
    protocol = "HTTPS"
    port = 80
    default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.test.arn
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

HTTP Port Open

The HTTP port (80) should not be open to the world in an AWS VPC Security Group. HTTPS which protects the integrity and confidentiality of transmitted data is the preferred option for HTTP traffic.

If you are transferring data of a sensitive nature then HTTPS should generally always be used. Sensitive data includes but is not limited to such items as:

  • Personally Identifiable Information
  • Login/authentication details
  • Passwords, secret keys
  • Credit card numbers

If you are not transferring any sensitive content, then besides concerns such as Search Engine Optimisation (SEO) and similar non-security related topics, Using HTTPS is less of an issue.

Rule-specific references:

Option A: Consider closing HTTP ingress port (80)

All aws_security_group.ingress rules should not have port 80 open to the world.

  1. Locate one of the following vulnerable patterns:

    resource "aws_security_group" "positive1" {
    name = "http_positive_tcp_1"
    description = "Gets the HTTP port open with the tcp protocol"

    ingress {
    description = "HTTP port open"
    from_port = 78
    to_port = 91
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    }
    }

    resource "aws_security_group" "positive2" {
    name = "http_positive_tcp_2"
    description = "Gets the HTTP port open with the tcp protocol"

    ingress {
    description = "HTTP port open"
    from_port = 60
    to_port = 85
    protocol = "tcp"
    cidr_blocks = ["0.0.0.2/0"]
    }

    ingress {
    description = "HTTP port open"
    from_port = 65
    to_port = 81
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    }
    }
  2. Modify the config to something like the following:

    resource "aws_security_group" "negative1" {
    name = "negative_http"
    description = "Doesn't get the HTTP port open"
    }

    resource "aws_security_group" "negative2" {

    ingress {
    from_port = 70
    to_port = 81
    protocol = "tcp"
    }
    }

    resource "aws_security_group" "negative3" {

    ingress {
    from_port = 79
    to_port = 100
    protocol = "tcp"
    cidr_blocks = ["0.1.0.0/0"]
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

S3 Bucket Policy Accepts HTTP Requests

S3 Bucket policy should not accept HTTP Requests.

Rule-specific references:

Option A: Only allow encrypted requests to S3 Bucket

To determine HTTP or HTTPS requests in a bucket policy, use a condition that checks for the key "aws:SecureTransport". When this key is true, then the request is sent through HTTPS. To comply with the s3-bucket-ssl-requests-only rule, create a bucket policy that explicitly denies access when the request meets the condition "aws:SecureTransport": "false". (AWS resource).

  1. Locate the following vulnerable pattern:

    Vulnerable aws_s3_bucket_policy Pattern:

    resource "aws_s3_bucket" "b" {
    bucket = "my-tf-test-bucket"
    }

    resource "aws_s3_bucket_policy" "b" {
    bucket = aws_s3_bucket.b.id

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
    "aws_s3_bucket.b.arn"
    ],
    "Condition": {
    "IpAddress": {
    "aws:SourceIp": "8.8.8.8/32"
    }
    }
    }
    ]
    }
    EOF
    }

    Vulnerable aws_s3_bucket with embedded policy Pattern:

    resource "aws_s3_bucket" "b2" {
    bucket = "my-tf-test-bucket"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
    "aws_s3_bucket.b.arn"
    ],
    "Condition": {
    "IpAddress": {
    "aws:SourceIp": "8.8.8.8/32"
    }
    }
    }
    ]
    }
    EOF
    }

    Vulnerable module s3_bucket with embedded policy Pattern:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
    "aws_s3_bucket.b.arn"
    ],
    "Condition": {
    "IpAddress": {
    "aws:SourceIp": "8.8.8.8/32"
    }
    }
    }
    ]
    }
    EOF
    }
  2. Modify the config to something like one of the following:

    A Policy that explicitly denies access to HTTP requests. I.E. if secure transport is false then deny:

    Replacement aws_s3_bucket_policy pattern:

    resource "aws_s3_bucket" "b" {
    bucket = "my-tf-test-bucket"
    }

    resource "aws_s3_bucket_policy" "b" {
    bucket = aws_s3_bucket.b.id

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
    "aws_s3_bucket.b.arn"
    ],
    "Condition": {
    "Bool": {
    "aws:SecureTransport": "false"
    }
    }
    }
    ]
    }
    EOF
    }

    Replacement aws_s3_bucket with embedded policy pattern:

    resource "aws_s3_bucket" "b2" {
    bucket = "my-tf-test-bucket"

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
    "aws_s3_bucket.b.arn"
    ],
    "Condition": {
    "Bool": {
    "aws:SecureTransport": "false"
    }
    }
    }
    ]
    }
    EOF
    }

    Replacement module s3_bucket with embedded policy pattern:

    module "s3_bucket" {
    source = "terraform-aws-modules/s3-bucket/aws"
    version = "3.7.0"

    bucket = "my-s3-bucket"
    acl = "private"

    versioning = {
    enabled = true
    }

    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Id": "MYBUCKETPOLICY",
    "Statement": [
    {
    "Sid": "IPAllow",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
    "aws_s3_bucket.b.arn"
    ],
    "Condition": {
    "Bool": {
    "aws:SecureTransport": "false"
    }
    }
    }
    ]
    }
    EOF
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Securing TLS configuration

About Insecure TLS Configuration

What is insecure TLS configuration?

Insecure TLS (Transport Layer Security) configuration refers to the use of weak or vulnerable cryptographic algorithms or protocols in the configuration of TLS on a system or application.

TLS is used to secure communication channels between clients and servers. Insecure TLS configuration can lead to a range of security vulnerabilities.

Check out these videos for a high-level explanation:

  • Weak Algorithms

  • Weak Cipher Suites

What is the impact of insecure TLS configuration?

Insecure TLS (Transport Layer Security) configuration can have significant impacts on the security and privacy of communication channels between clients and servers.

Here are some of the potential impacts:

  • Man-in-the-middle (MITM) attacks: Weak or outdated cryptographic algorithms can be exploited by attackers to intercept and modify data in transit between a client and server. This can enable attackers to steal sensitive data or manipulate communication channels to launch other attacks.
  • Information disclosure: Insecure TLS configuration can allow attackers to gain access to sensitive data, such as login credentials or personal information, transmitted between the client and server. This can lead to data breaches or compromise of sensitive information.

How to prevent insecure TLS configuration?

To prevent insecure TLS (Transport Layer Security) configuration, several measures can be taken, including:

  • Use strong cryptographic algorithms and protocols: Use strong cryptographic algorithms and protocols, such as TLS 1.2 or higher, and disable outdated or weak algorithms, such as SSLv2 and SSLv3. This can help prevent attackers from exploiting vulnerabilities in the encryption and authentication processes.
  • Use appropriate key sizes: Use appropriate key sizes to ensure that the cryptographic keys used in the TLS communication are strong enough to resist attacks. Key sizes of 2048 bits or higher are recommended.
  • Regularly update software and systems: Regularly update software and systems to ensure that the latest security patches are applied and known vulnerabilities are addressed.

References

Taxonomies

Explanation & Prevention

Training

Ensure Secure SSL/TLS Configuration

Even though SSL/TLS is configured for certain services, it may be configured insecurely and as a result increase the risk of getting intercepted.

Option A: Use correct SSL/TLS policy for AWS ELB

  1. Go through the issues that GuardRails identified

  2. Identify the SSL/TLS related for the aws_lb_listener

    resource "aws_lb_listener" "front_end" {
    load_balancer_arn = aws_lb.front_end.arn
    port = "443"
    protocol = "HTTPS"
    ssl_policy = "ELBSecurityPolicy-2016-08"
    certificate_arn = "arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4"

    default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.front_end.arn
    }
    }
  3. Make sure to avoid the following SSL Policies:

    ELBSecurityPolicy-2015-05
    ELBSecurityPolicy-TLS-1-0-2015-04
    ELBSecurityPolicy-2016-08
    ELBSecurityPolicy-TLS-1-1-2017-01

    Instead, it is recommended to use:

    TLS-1-2-2017-01
  4. Test it

  5. Ship it 🚢 and relax 🌴

Option B: Use secure minimum_protocol_version of TLS for CloudFront

  1. Go through the issues that GuardRails identified

  2. Identify the SSL/TLS related for the aws_cloudfront_distribution

  3. Ensure that the viewer_certificate is configured securely

    viewer_certificate {
    ...
    minimum_protocol_version = TLSv1.2_2019
    }

Option C: Use correct security policy for AWS API Gateway

  1. Go through the issues that GuardRails identified

  2. Locate the aws_api_gateway_domain_name resource and the security_policy if it exists

    resource "aws_api_gateway_domain_name" "example" {
    domain_name = "api.example.com"
    regional_certificate_name = "example-api"
    ...
    }
  3. Change the security_policy to TLS_1_2

    resource "aws_api_gateway_domain_name" "example" {
    domain_name = "api.example.com"
    regional_certificate_name = "example-api"
    ...
    security_policy = "TLS_1_2"
    }

App Service Not Using Latest TLS Encryption Version

Ensure Azure App Service is using the latest version of TLS encryption.

Rule-specific references:

Option A: Make sure Azure App Service Site Config Min TLS Version is the latest value

resource azurerm_app_service site_config.min_tls_version should be the latest value.

  1. Locate the following vulnerable pattern:

    resource "azurerm_app_service" "positive1" {
    name = "example-app-service"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id

    site_config {
    dotnet_framework_version = "v4.0"
    scm_type = "LocalGit"
    min_tls_version = 1.1
    }
    }
  2. Modify the config to something like the following:

    Replacement using site_config explicit latest value:

    resource "azurerm_app_service" "negative1" {
    name = "example-app-service"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id

    site_config {
    dotnet_framework_version = "v4.0"
    scm_type = "LocalGit"
    min_tls_version = 1.2
    }
    }

    Replacement using site_config default latest value:

    resource "azurerm_app_service" "negative1" {
    name = "example-app-service"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id

    site_config {
    dotnet_framework_version = "v4.0"
    scm_type = "LocalGit"
    }
    }

    Replacement using default latest value:

    resource "azurerm_app_service" "negative3" {
    name = "example-app-service"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

CloudFront Without Minimum Protocol TLS 1.2

CloudFront Minimum Protocol version should be at least TLS 1.2.

Rule-specific references:

Option A: Make sure CloudFront Minimum Protocol Version is at least TLS 1.2

  • Check that any resource aws_cloudfront_distribution.viewer_certificate.minimum_protocol_version is defined and value is at least TLSv1.2_x (Ex: "TLSv1.2_2018", "TLSv1.2_2019", "TLSv1.2_2021")
  • And that any resource aws_cloudfront_distribution.viewer_certificate.cloudfront_default_certificate is false
  1. Locate the following vulnerable patterns:

    Vulnerable no viewer_certificate block pattern:

    resource "aws_cloudfront_distribution" "positive1" {
    origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id = local.s3_origin_id

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true
    comment = "Some comment"
    default_root_object = "index.html"

    default_cache_behavior {
    #settings
    }

    restrictions {
    #restrictions
    }
    }

    Vulnerable specific minimum_protocol_version too low pattern:

    resource "aws_cloudfront_distribution" "positive2" {
    origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id = local.s3_origin_id

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true
    comment = "Some comment"
    default_root_object = "index.html"

    default_cache_behavior {
    #settings
    }

    restrictions {
    #restrictions
    }

    viewer_certificate {
    cloudfront_default_certificate = false
    minimum_protocol_version = "TLSv1_2016"
    }
    }

    Vulnerable minimum_protocol_version not defined, with cloudfront_default_certificate = true pattern:

    resource "aws_cloudfront_distribution" "positive3" {
    origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id = local.s3_origin_id

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true
    comment = "Some comment"
    default_root_object = "index.html"

    default_cache_behavior {
    #settings
    }

    restrictions {
    #restrictions
    }

    viewer_certificate {
    cloudfront_default_certificate = true
    }
    }

    Vulnerable minimum_protocol_version not defined, with cloudfront_default_certificate = false pattern:

    resource "aws_cloudfront_distribution" "positive4" {
    origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id = local.s3_origin_id

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true
    comment = "Some comment"
    default_root_object = "index.html"

    default_cache_behavior {
    #settings
    }

    restrictions {
    #restrictions
    }

    viewer_certificate {
    cloudfront_default_certificate = false
    }
    }
  2. Modify the config to something like one of the following:

    Replacement good (minimum_protocol_version = "TLSv1.2_2018") pattern:

    resource "aws_cloudfront_distribution" "negative1" {
    origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id = local.s3_origin_id

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true
    comment = "Some comment"
    default_root_object = "index.html"

    default_cache_behavior {
    allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = local.s3_origin_id

    forwarded_values {
    query_string = false

    cookies {
    forward = "none"
    }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl = 0
    default_ttl = 3600
    max_ttl = 86400
    }

    restrictions {
    geo_restriction {
    restriction_type = "whitelist"
    locations = ["US", "CA", "GB", "DE"]
    }
    }

    viewer_certificate {
    cloudfront_default_certificate = false
    minimum_protocol_version = "TLSv1.2_2018"
    }
    }

    Replacement better (minimum_protocol_version = "TLSv1.2_2019") pattern:

    resource "aws_cloudfront_distribution" "negative2" {
    origin {
    domain_name = aws_s3_bucket.b.bucket_regional_domain_name
    origin_id = local.s3_origin_id

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true
    comment = "Some comment"
    default_root_object = "index.html"

    default_cache_behavior {
    allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = local.s3_origin_id

    forwarded_values {
    query_string = false

    cookies {
    forward = "none"
    }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl = 0
    default_ttl = 3600
    max_ttl = 86400
    }

    restrictions {
    geo_restriction {
    restriction_type = "whitelist"
    locations = ["US", "CA", "GB", "DE"]
    }
    }

    viewer_certificate {
    cloudfront_default_certificate = false
    minimum_protocol_version = "TLSv1.2_2019"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Function App Not Using Latest TLS Encryption Version

Ensure Function App is using the latest version of TLS encryption.

Rule-specific references:

Option A: Azure Function App Site Config Min TLS Version should be set to 1.2

Make sure resource azurerm_function_app site_config.min_tls_version is set to 1.2 specifically or by default.

  1. Locate the following vulnerable pattern:

    resource "azurerm_function_app" "positive1" {
    name = "test-azure-functions"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id
    storage_account_name = azurerm_storage_account.example.name
    storage_account_access_key = azurerm_storage_account.example.primary_access_key

    site_config {
    dotnet_framework_version = "v4.0"
    scm_type = "LocalGit"
    min_tls_version = 1.1
    }
    }
  2. Modify the config to something like one of the following:

    Replacement pattern using specific min_tls_version:

    resource "azurerm_function_app" "negative1" {
    name = "test-azure-functions"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id
    storage_account_name = azurerm_storage_account.example.name
    storage_account_access_key = azurerm_storage_account.example.primary_access_key

    site_config {
    dotnet_framework_version = "v4.0"
    scm_type = "LocalGit"
    min_tls_version = 1.2
    }
    }

    Replacement pattern using defailt min_tls_version with a site_config:

    resource "azurerm_function_app" "negative2" {
    name = "test-azure-functions"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id
    storage_account_name = azurerm_storage_account.example.name
    storage_account_access_key = azurerm_storage_account.example.primary_access_key

    site_config {
    dotnet_framework_version = "v4.0"
    scm_type = "LocalGit"
    }
    }

    Replacement pattern using default min_tls_version with no site_config:

    resource "azurerm_function_app" "negative3" {
    name = "test-azure-functions"
    location = azurerm_resource_group.example.location
    resource_group_name = azurerm_resource_group.example.name
    app_service_plan_id = azurerm_app_service_plan.example.id
    storage_account_name = azurerm_storage_account.example.name
    storage_account_access_key = azurerm_storage_account.example.primary_access_key
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

ELB Using Weak Ciphers

ELB Predefined or Custom Security Policies must not use weak ciphers, to reduce the risk of the SSL connection between the client and the load balancer being exploited. This means that the name of the policy_attribute must not coincide with any of a predefined list of weak ciphers.

Rule-specific references:

Option A: Locate out-of-date (known weak) cipher or policy and replace it with a strong cipher or policy

  1. Review the value of aws_load_balancer_policy policy_attribute.name. The value should be set to one of the known secure TLS ciphers. The default value (if not visibly present) of policy_attribute.name uses a known good TLS cipher

  2. If an out-of-date (less than optimal) cipher is being used replace it with a good one

  3. Locate one of the following vulnerable patterns:

    resource "aws_load_balancer_policy" "positive1" {
    load_balancer_name = aws_elb.wu-tang.name
    policy_name = "wu-tang-ssl"
    policy_type_name = "SSLNegotiationPolicyType"

    policy_attribute {
    name = "Protocol-TLSv1.2"
    value = "true"
    }

    policy_attribute {
    // Weak cipher.
    name = "TLS_RSA_ARCFOUR_128_SHA1"
    value = "true"
    }
    }

    resource "aws_load_balancer_policy" "positive2" {
    load_balancer_name = aws_elb.wu-tang.name
    policy_name = "wu-tang-ssl"
    policy_type_name = "SSLNegotiationPolicyType"

    policy_attribute {
    // Weak cipher.
    name = "DES-CBC3-SHA"
    value = "true"
    }
    }

    resource "aws_load_balancer_policy" "positive3" {
    load_balancer_name = aws_elb.wu-tang.name
    policy_name = "wu-tang-ssl"
    policy_type_name = "SSLNegotiationPolicyType"

    policy_attribute {
    // Weak cipher.
    name = "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384"
    value = "true"
    }
    }
  4. Modify the config to something like one of the following:

    resource "aws_load_balancer_policy" "negative1" {
    load_balancer_name = aws_elb.wu-tang.name
    policy_name = "wu-tang-ssl"
    policy_type_name = "SSLNegotiationPolicyType"

    policy_attribute {
    // Strong cipher.
    name = "ECDHE-ECDSA-AES128-GCM-SHA256"
    value = "true"
    }

    policy_attribute {
    // Strong policy.
    name = "Protocol-TLSv1.2"
    value = "true"
    }
    }

    resource "aws_load_balancer_policy" "negative2" {
    load_balancer_name = aws_elb.wu-tang.name
    policy_name = "wu-tang-ssl"
    policy_type_name = "SSLNegotiationPolicyType"

    policy_attribute {
    // Acceptable policy.
    name = "Reference-Security-Policy"
    value = "ELBSecurityPolicy-TLS-1-1-2017-01"
    }
    }
  5. Test it

  6. Ship it 🚢 and relax 🌴

Secure Ciphers Disabled

Check if secure ciphers aren't used in AWS CloudFront.

Rule-specific references:

Option A: Make sure the Minimum Protocol Version is not out-of-date and the default certificate is true

  • The aws_cloudfront_distribution viewer_certificate.minimum_protocol_version should be at least "TLSv1.1" but preferably more recent
  • The aws_cloudfront_distribution viewer_certificate.cloudfront_default_certificate should be true
  1. Locate the following vulnerable pattern:

    resource "aws_cloudfront_distribution" "positive1" {
    origin {
    domain_name = "mybucket"
    origin_id = "myS3Origin"

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true

    default_cache_behavior {
    allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = "myS3Origin"

    forwarded_values {
    query_string = false

    cookies {
    forward = "none"
    }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl = 0
    default_ttl = 3600
    max_ttl = 86400
    }

    restrictions {
    geo_restriction {
    restriction_type = "whitelist"
    locations = ["US", "CA", "GB", "DE"]
    }
    }

    viewer_certificate {
    // Vulnerable pattern: Viewers don't have to use HTTPS to request your objects.
    cloudfront_default_certificate = false
    // Protocol version too low.
    minimum_protocol_version = "SSLv3"
    }
    }
  2. Modify the config to something like the following:

    resource "aws_cloudfront_distribution" "negative1" {
    origin {
    domain_name = "mybucket"
    origin_id = "myS3Origin"

    s3_origin_config {
    origin_access_identity = "origin-access-identity/cloudfront/ABCDEFG1234567"
    }
    }

    enabled = true

    default_cache_behavior {
    allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods = ["GET", "HEAD"]
    target_origin_id = "myS3Origin"

    forwarded_values {
    query_string = false

    cookies {
    forward = "none"
    }
    }

    viewer_protocol_policy = "allow-all"
    min_ttl = 0
    default_ttl = 3600
    max_ttl = 86400
    }

    restrictions {
    geo_restriction {
    restriction_type = "whitelist"
    locations = ["US", "CA", "GB", "DE"]
    }
    }

    viewer_certificate {
    // Viewers must use HTTPS to request your objects.
    cloudfront_default_certificate = true
    // Protocol version starts with TLSv1.2
    minimum_protocol_version = "TLSv1.2_2019"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Storage Account Not Using Latest TLS Encryption Version

Ensure Storage Account is using the latest version of TLS encryption.

Rule-specific references:

Option A: Make sure the Minimum Storage Account TLS Version is set correctly

The azurerm_storage_account min_tls_version Should be defined and have a value of at least "TLS1_2". If the min_tls_version is not defined, new storage accounts will default to "TLS1_2" which is actually good, but will incorrectly fail this rule. To work around this simply be specific about the min_tls_version.

  1. Locate one of the following vulnerable patterns:

    resource "azurerm_storage_account" "positive1" {
    name = "storageaccountname"
    resource_group_name = azurerm_resource_group.example.name
    location = azurerm_resource_group.example.location
    account_tier = "Standard"
    account_replication_type = "GRS"
    // Vulnerable.
    min_tls_version = "TLS1_1"

    tags = {
    environment = "staging"
    }
    }
  2. Modify the config to something like the following:

    resource "azurerm_storage_account" "negative1" {
    name = "storageaccountname"
    resource_group_name = azurerm_resource_group.example.name
    location = azurerm_resource_group.example.location
    account_tier = "Standard"
    account_replication_type = "GRS"
    // Not Vulnerable.
    min_tls_version = "TLS1_2"

    tags = {
    environment = "staging"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴