Skip to main content

Insecure Authentication

Fixing Insecure Authentication

About Insecure Authentication

What is improper authentication?

Improper authentication is a security weakness that occurs when a system does not properly verify the identity of users or entities attempting to access it. Improper authentication can occur in various forms, such as no password, weak or easily guessed passwords, absence of multi-factor authentication, lack of session timeouts, etc.

Inadequate authentication mechanisms can allow unauthorized users to gain access to a system, potentially leading to data breaches, data loss, or unauthorized access to sensitive resources.

Examples of improper authentication vulnerabilities include:

  • No authentication: When there is no authentication for a critical function, then attackers get unrestricted access easily.
  • Weak passwords: When users choose weak passwords, it makes it easier for attackers to guess or crack them.
  • Lack of multi-factor authentication: Multi-factor authentication, such as using a password and a one-time code sent to a user's mobile device, can provide an extra layer of security. If multi-factor authentication is not used, an attacker who has obtained a user's password can gain access to the system.
  • Lack of session timeouts: When users do not log out of the system, the session may remain active, allowing an attacker to hijack the session and gain access to the system.

Check out this video for a high-level explanation:

What is the impact of improper authentication?

Improper authentication can lead to various security threats, such as:

  • Data breaches: Improper authentication can allow unauthorized users to gain access to sensitive data, leading to data breaches, data loss, or unauthorized access to confidential information.
  • Unauthorized access to resources: Attackers can exploit improper authentication to gain unauthorized access to resources, such as servers, databases, and applications.
  • Impersonation of legitimate users: Attackers can use stolen or weak credentials to impersonate legitimate users and perform actions on their behalf.
  • Account takeover: Attackers can use improper authentication to take over user accounts and gain access to sensitive data or resources.
  • Compliance violations: Improper authentication can lead to violations of regulatory compliance requirements, such as data protection regulations.
  • Reputation damage: A successful attack exploiting improper authentication can lead to loss of customer trust and reputational damage for the organization.

How to prevent improper authentication?

To prevent improper authentication vulnerabilities, it is essential to implement secure authentication mechanisms that verify the identity of users and entities attempting to access the system.

Here are some measures that can help prevent improper authentication:

  • Strong passwords: Implement password policies that require users to choose strong, unique, and complex passwords. This can include length requirements, character complexity requirements, and password expiration policies.
  • Multi-factor authentication: Use multi-factor authentication to provide an extra layer of security. This can include using a password and a one-time code sent to a user's mobile device or using biometric authentication.
  • Session timeouts: Implement session timeouts to ensure that users are automatically logged out of the system after a certain period of inactivity. This can help prevent unauthorized access to the system through hijacked sessions.
  • Access controls: Implement access controls that restrict access to sensitive resources and data based on user roles and permissions. This can help prevent unauthorized access to sensitive information or systems.
  • User education: Educate users about the importance of strong passwords, multi-factor authentication, and other best practices for secure authentication. This can include regular reminders, training, and awareness campaigns.
  • Regular security audits: Regularly audit your system for security vulnerabilities, including improper authentication vulnerabilities. Use automated tools and manual testing to identify potential issues and fix them before they can be exploited.

References

Taxonomies

Explanation & Prevention

Training

Using Default Service Account

Google Compute Instances must not be configured to use the Default Service Account, which has full access to all Cloud APIs, which means the attribute service_account and its sub-attribute email must be defined. Additionally, email must not be empty and must also not be a default Google Compute Engine service account.

This rule is violated if any of the following conditions are false:

  • google_compute_instance service_account must be defined and not null
  • google_compute_instance service_account.email must be defined and not null
  • google_compute_instance service_account.email must not be empty
  • google_compute_instance service_account.email must not be a default Google Compute Engine service account
  • google_compute_instance service_account.email must be a valid email address

Rule-specific references:

Option A: Make sure none of the above conditions are true

From the following vulnerable patterns, replace them with a non-vulnerable pattern.

  1. Locate one of the following vulnerable patterns:

    Vulnerable service_account is undefined pattern:

    resource "google_compute_instance" "positive1" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    tags = ["foo", "bar"]

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    network_interface {
    network = "default"

    access_config {
    // Ephemeral IP
    }
    }

    }

    Vulnerable service_account.email is undefined pattern:

    resource "google_compute_instance" "positive2" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    tags = ["foo", "bar"]

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    network_interface {
    network = "default"

    access_config {
    // Ephemeral IP
    }
    }

    service_account {
    scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
    }

    Vulnerable service_account.email is empty pattern:

    resource "google_compute_instance" "positive3" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    tags = ["foo", "bar"]

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    network_interface {
    network = "default"

    access_config {
    // Ephemeral IP
    }
    }

    service_account {
    email = ""
    scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
    }

    Vulnerable service_account.email is not a valid email address pattern:

    resource "google_compute_instance" "positive4" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    tags = ["foo", "bar"]

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    network_interface {
    network = "default"

    access_config {
    // Ephemeral IP
    }
    }

    service_account {
    email = "a"
    scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
    }

    Vulnerable service_account.email is a default Google Compute Engine service account pattern:

    resource "google_compute_instance" "positive5" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    tags = ["foo", "bar"]

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    network_interface {
    network = "default"

    access_config {
    // Ephemeral IP
    }
    }

    service_account {
    email = "[email protected]"
    scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
    }
  2. Modify the config to something like the following:

    resource "google_compute_instance" "negative1" {
    name = "test"
    machine_type = "e2-medium"
    zone = "us-central1-a"

    tags = ["foo", "bar"]

    boot_disk {
    initialize_params {
    image = "debian-cloud/debian-9"
    }
    }

    // Local SSD disk
    scratch_disk {
    interface = "SCSI"
    }

    network_interface {
    network = "default"

    access_config {
    // Ephemeral IP
    }
    }

    service_account {
    email = "[email protected]"
    scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

GKE Using Default Service Account

Kubernetes Engine Clusters should not be configured to use the default service account.

Rule-specific references:

Option A: Make sure to specify a non-default Service Account

If no resource google_container_cluster.node_config.service_account is specified for the cluster nodes, the "default" service account is used.

  1. Locate the following vulnerable pattern:

    Vulnerable default service_account pattern:

    resource "google_container_cluster" "positive1" {
    name = "my-gke-cluster"
    location = "us-central1"
    remove_default_node_pool = true
    initial_node_count = 1

    node_config {
    oauth_scopes = [
    "https://www.googleapis.com/auth/cloud-platform"
    ]
    labels = {
    foo = "bar"
    }
    tags = ["foo", "bar"]
    }
    timeouts {
    create = "30m"
    update = "40m"
    }
    }

    Vulnerable default service_account pattern by being specific:

    resource "google_container_cluster" "positive2" {
    name = "my-gke-cluster"
    location = "us-central1"
    remove_default_node_pool = true
    initial_node_count = 1

    node_config {
    service_account = google_service_account.default.email
    oauth_scopes = [
    "https://www.googleapis.com/auth/cloud-platform"
    ]
    labels = {
    foo = "bar"
    }
    tags = ["foo", "bar"]
    }
    timeouts {
    create = "30m"
    update = "40m"
    }
    }
  2. Modify the config to something like the following:

    Replacement specific custom service_account pattern:

    resource "google_container_cluster" "negative1" {
    name = "my-gke-cluster"
    location = "us-central1"
    remove_default_node_pool = true
    initial_node_count = 1

    node_config {
    service_account = google_service_account.myserviceaccount.email
    oauth_scopes = [
    "https://www.googleapis.com/auth/cloud-platform"
    ]
    labels = {
    foo = "bar"
    }
    tags = ["foo", "bar"]
    }
    timeouts {
    create = "30m"
    update = "40m"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

EC2 Instance Using API Keys

EC2 instances should use roles to be granted access to other AWS services.

Rule-specific references:

Option A: Remove API keys from EC2 instances

  • Do not include API keys in user_data whether encoded or not
  • Do not include API keys in an EC2 instance by using a "remote-exec" provisioner
  • Do not include API keys in an EC2 instance by using a "file" provisioner
  1. Locate any of the following vulnerable patterns:

    Do not insert API keys into user_data as environment variables:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive1" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    user_data = <<EOF
    #!/bin/bash
    apt-get install -y awscli
    export AWS_ACCESS_KEY_ID=your_access_key_id_here
    export AWS_SECRET_ACCESS_KEY=your_secret_access_key_here
    EOF

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Do not insert API keys in user_data so that they are inserted into configuration files:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive2" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    user_data = <<EOT
    #!/bin/bash
    apt-get install -y awscli
    cat << EOF > ~/.aws/config
    [default]
    aws_access_key_id = somekey
    aws_secret_access_key = somesecret
    EOF
    EOT

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Do not insert API keys into user_data so that they are inserted into credentials files:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive3" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    user_data = <<EOT
    #!/bin/bash
    apt-get install -y awscli
    cat << EOF > ~/.aws/credentials
    [default]
    aws_access_key_id = somekey
    aws_secret_access_key = somesecret
    EOF
    EOT

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Do not insert API keys into user_data_base64. Encoding provides no security:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive4" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    user_data_base64 = var.init_aws_cli

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Or a similar example using user_data_base64:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive5" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    user_data_base64 = base64encode("apt-get install -y awscli; export AWS_ACCESS_KEY_ID=your_access_key_id_here; export AWS_SECRET_ACCESS_KEY=your_secret_access_key_here")

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Do not insert API keys into user_data by inserting them as environment variables into a shell configuration file:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive6" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    user_data = <<EOT
    #cloud-config
    repo_update: true
    repo_upgrade: all

    packages:
    - awscli

    runcmd:
    - [ sh, -c, "echo export AWS_ACCESS_KEY_ID=my-key-id >> ~/.bashrc" ]
    - [ sh, -c, "echo export AWS_SECRET_ACCESS_KEY=my-secret >> ~/.bashrc" ]
    EOT

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Do not insert API keys into EC2 instance credentials file using "remote-exec" provisioner:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive7" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    provisioner "remote-exec" {
    inline = [
    "wget -O - http://config.remote.server.com/aws-credentials > ~/.aws/credentials;"
    ]
    }

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Do not insert API keys into EC2 instance credentials file using "file" provisioner:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive8" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    provisioner "file" {
    source = "conf/aws-credentials"
    destination = "~/.aws/credentials"
    }
    }

    Do not insert API keys into EC2 instance shell configuration file using "remote-exec" provisioner:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_instance" "positive9" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    provisioner "remote-exec" {
    inline = [
    "echo export AWS_ACCESS_KEY_ID=my-key-id >> ~/.bashrc",
    "echo export AWS_SECRET_ACCESS_KEY=my-secret >> ~/.bashrc"
    ]
    }

    credit_specification {
    cpu_credits = "unlimited"
    }
    }
  2. Modify the config to something like the following:

    Using a role via iam_instance_profile:

    provider "aws" {
    region = "us-east-1"
    }

    resource "aws_iam_role_policy_attachment" "test_attach" {
    roles = [aws_iam_role.test_role.name]
    policy_arn = aws_iam_policy.test_policy.arn
    }

    resource "aws_iam_policy" "test_policy" {
    name = "test_policy"
    description = "test policy"
    path = "/"
    policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": [
    "s3:Get*",
    "s3:List*"
    ],
    "Effect": "Allow",
    "Resource": "*"
    }
    ]
    }
    EOF
    }

    resource "aws_iam_role" "test_role" {
    name = "test_role"
    path = "/"

    assume_role_policy = <<EOF
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Action": "sts:AssumeRole",
    "Principal": {
    "Service": "ec2.amazonaws.com"
    },
    "Effect": "Allow",
    "Sid": ""
    }
    ]
    }
    EOF
    }

    resource "aws_iam_instance_profile" "test_profile" {
    name = "test_profile"
    role = aws_iam_role.role.name
    }

    resource "aws_instance" "negative1" {
    ami = "ami-005e54dee72cc1d00" # us-west-2
    instance_type = "t2.micro"

    tags = {
    Name = "test"
    }

    iam_instance_profile = aws_iam_instance_profile.test_profile.name

    credit_specification {
    cpu_credits = "unlimited"
    }
    }

    Or just remove them altogether:

    module "ec2_instance" {
    source = "terraform-aws-modules/ec2-instance/aws"
    version = "~> 3.0"

    name = "single-instance"

    ami = "ami-ebd02392"
    instance_type = "t2.micro"
    key_name = "user1"
    monitoring = true
    vpc_security_group_ids = ["sg-12345678"]
    subnet_id = "subnet-eddcdzz4"

    tags = {
    Terraform = "true"
    Environment = "dev"
    }
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴

Default Service Account In Use

Default service accounts should not be actively used.

resource kubernetes_service_account automount_service_account_token should be defined and set to false.

Rule-specific references:

Option A: Opt-out of automounting API credentials for a service account

Opt-out of automounting API credentials for a service account by defining and setting resource kubernetes_service_account automount_service_account_token to be false.

  1. Locate the following vulnerable pattern:

    resource "kubernetes_service_account" "example" {
    metadata {
    name = "default"
    }
    }

    resource "kubernetes_service_account" "example2" {
    metadata {
    name = "default"
    }

    automount_service_account_token = true
    }
  2. Modify the config to something like the following:

    resource "kubernetes_service_account" "example3" {
    metadata {
    name = "default"
    }

    automount_service_account_token = false
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴