Serverless.com Security

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Basic Information

Organization

An Organization is the highest-level entity within the Serverless Framework ecosystem. It represents a collective group, such as a company, department, or any large entity, that encompasses multiple projects, teams, and applications.

Team

The Team are the users with access inside the organization. Teams help in organizing members based on roles. Collaborators can view and deploy existing apps, while Admins can create new apps and manage organization settings.

Application

An App is a logical grouping of related services within an Organization. It represents a complete application composed of multiple serverless services that work together to provide a cohesive functionality.

Services

A Service is the core component of a Serverless application. It represents your entire serverless project, encapsulating all the functions, configurations, and resources needed. It's typically defined in a serverless.yml file, a service includes metadata like the service name, provider configurations, functions, events, resources, plugins, and custom variables.

service: my-service
provider:
  name: aws
  runtime: nodejs14.x
functions:
  hello:
    handler: handler.hello
Function

A Function represents a single serverless function, such as an AWS Lambda function. It contains the code that executes in response to events.

It's defined under the functions section in serverless.yml, specifying the handler, runtime, events, environment variables, and other settings.

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
Event

Events are triggers that invoke your serverless functions. They define how and when a function should be executed.

Common event types include HTTP requests, scheduled events (cron jobs), database events, file uploads, and more.

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
      - schedule:
          rate: rate(10 minutes)
Resource

Resources allow you to define additional cloud resources that your service depends on, such as databases, storage buckets, or IAM roles.

They are specified under the resources section, often using CloudFormation syntax for AWS.

resources:
  Resources:
    MyDynamoDBTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: my-table
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
Provider

The Provider object specifies the cloud service provider (e.g., AWS, Azure, Google Cloud) and contains configuration settings relevant to that provider.

It includes details like the runtime, region, stage, and credentials.

yamlCopy codeprovider:
  name: aws
  runtime: nodejs14.x
  region: us-east-1
  stage: dev
Stage and Region

The stage represents different environments (e.g., development, staging, production) where your service can be deployed. It allows for environment-specific configurations and deployments.

provider:
  stage: dev

The region specifies the geographical region where your resources will be deployed. It's important for latency, compliance, and availability considerations.

provider:
  region: us-west-2
Plugins

Plugins extend the functionality of the Serverless Framework by adding new features or integrating with other tools and services. They are defined under the plugins section and installed via npm.

plugins:
  - serverless-offline
  - serverless-webpack
Layers

Layers allow you to package and manage shared code or dependencies separately from your functions. This promotes reusability and reduces deployment package sizes. They are defined under the layers section and referenced by functions.

layers:
  commonLibs:
    path: layer-common
functions:
  hello:
    handler: handler.hello
    layers:
      - { Ref: CommonLibsLambdaLayer }
Variables and Custom Variables

Variables enable dynamic configuration by allowing the use of placeholders that are resolved at deployment time.

  • Syntax: ${variable} syntax can reference environment variables, file contents, or other configuration parameters.

    functions:
      hello:
        handler: handler.hello
        environment:
          TABLE_NAME: ${self:custom.tableName}
  • Custom Variables: The custom section is used to define user-specific variables and configurations that can be reused throughout the serverless.yml.

    custom:
      tableName: my-dynamodb-table
      stage: ${opt:stage, 'dev'}
Outputs

Outputs define the values that are returned after a service is deployed, such as resource ARNs, endpoints, or other useful information. They are specified under the outputs section and often used to expose information to other services or for easy access post-deployment.

¡outputs:
  ApiEndpoint:
    Description: "API Gateway endpoint URL"
    Value:
      Fn::Join:
        - ""
        - - "https://"
          - Ref: ApiGatewayRestApi
          - ".execute-api."
          - Ref: AWS::Region
          - ".amazonaws.com/"
          - Ref: AWS::Stage
IAM Roles and Permissions

IAM Roles and Permissions define the security credentials and access rights for your functions and other resources. They are managed under the provider or individual function settings to specify necessary permissions.

provider:
  [...]
  iam:
    role:
      statements:
        - Effect: 'Allow'
          Action:
            - 'dynamodb:PutItem'
            - 'dynamodb:Get*'
            - 'dynamodb:Scan*'
            - 'dynamodb:UpdateItem'
            - 'dynamodb:DeleteItem'
          Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
Environment Variables

Variables allow you to pass configuration settings and secrets to your functions without hardcoding them. They are defined under the environment section for either the provider or individual functions.

provider:
  environment:
    STAGE: ${self:provider.stage}
functions:
  hello:
    handler: handler.hello
    environment:
      TABLE_NAME: ${self:custom.tableName}
Dependencies

Dependencies manage the external libraries and modules your functions require. They typically handled via package managers like npm or pip, and bundled with your deployment package using tools or plugins like serverless-webpack.

plugins:
  - serverless-webpack
Hooks

Hooks allow you to run custom scripts or commands at specific points in the deployment lifecycle. They are defined using plugins or within the serverless.yml to perform actions before or after deployments.

custom:
  hooks:
    before:deploy:deploy: echo "Starting deployment..."

Tutorial

This is a summary of the official tutorial from the docs:

  1. Create an AWS account (Serverless.com start in AWS infrastructure)

  2. Create an account in serverless.com

  3. Create an app:

# Create temp folder for the tutorial
mkdir /tmp/serverless-tutorial
cd /tmp/serverless-tutorial

# Install Serverless cli
npm install -g serverless

# Generate template
serverless #Choose first one (AWS / Node.js / HTTP API)
## Indicate a name like "Tutorial"
## Login/Register
## Create A New App
## Indicate a name like "tutorialapp)

This should have created an app called tutorialapp that you can check in serverless.com and a folder called Tutorial with the file handler.js containing some JS code with a helloworld code and the file serverless.yml declaring that function:

exports.hello = async (event) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: "Go Serverless v4! Your function executed successfully!",
    }),
  };
};
  1. Create an AWS provider, going in the dashboard in https://app.serverless.com/<org name>/settings/providers?providerId=new&provider=aws.

    1. To give serverless.com access to AWS It will ask to run a cloudformation stack using this config file (at the time of this writing): https://serverless-framework-template.s3.amazonaws.com/roleTemplate.yml

    2. This template generates a role called SFRole-<ID> with arn:aws:iam::aws:policy/AdministratorAccess over the account with a Trust Identity that allows Serverless.com AWS account to access the role.

Yaml roleTemplate
Description: This stack creates an IAM role that can be used by Serverless Framework for use in deployments.
Resources:
  SFRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS: arn:aws:iam::486128539022:root
            Action:
              - sts:AssumeRole
            Condition:
              StringEquals:
                sts:ExternalId: !Sub 'ServerlessFramework-${OrgUid}'
      Path: /
      RoleName: !Ref RoleName
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AdministratorAccess
  ReporterFunction:
    Type: Custom::ServerlessFrameworkReporter
    Properties:
      ServiceToken: 'arn:aws:lambda:us-east-1:486128539022:function:sp-providers-stack-reporter-custom-resource-prod-tmen2ec'
      OrgUid: !Ref OrgUid
      RoleArn: !GetAtt SFRole.Arn
      Alias: !Ref Alias
Outputs:
  SFRoleArn:
    Description: 'ARN for the IAM Role used by Serverless Framework'
    Value: !GetAtt SFRole.Arn
Parameters:
  OrgUid:
    Description: Serverless Framework Org Uid
    Type: String
  Alias:
    Description: Serverless Framework Provider Alias
    Type: String
  RoleName:
    Description: Serverless Framework Role Name
    Type: String
Trust Relationship
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::486128539022:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "sts:ExternalId": "ServerlessFramework-7bf7ddef-e1bf-43eb-a111-4d43e0894ccb"
                }
            }
        }
    ]
}
  1. The tutorial asks to create the file createCustomer.js which will basically create a new API endpoint handled by the new JS file and asks to modify the serverless.yml file to make it generate a new DynamoDB table, define an environment variable, the role that will be using the generated lambdas.

'use strict'
const AWS = require('aws-sdk')
module.exports.createCustomer = async (event) => {
  const body = JSON.parse(Buffer.from(event.body, 'base64').toString())
  const dynamoDb = new AWS.DynamoDB.DocumentClient()
  const putParams = {
    TableName: process.env.DYNAMODB_CUSTOMER_TABLE,
    Item: {
      primary_key: body.name,
      email: body.email,
    },
  }
  await dynamoDb.put(putParams).promise()
  return {
    statusCode: 201,
  }
}
  1. Deploy it running serverless deploy

    1. The deployment will be performed via a CloudFormation Stack

    2. Note that the lambdas are exposed via API gateway and not via direct URLs

  2. Test it

    1. The previous step will print the URLs where your API endpoints lambda functions have been deployed

Security Review of Serverless.com

Misconfigured IAM Roles and Permissions

Overly permissive IAM roles can grant unauthorized access to cloud resources, leading to data breaches or resource manipulation.

When no permissions are specified for the a Lambda function, a role with permissions only to generate logs will be created, like:

Minimum lambda permissions
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogStream",
                "logs:CreateLogGroup",
                "logs:TagResource"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/jito-cranker-scripts-dev*:*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/jito-cranker-scripts-dev*:*:*"
            ],
            "Effect": "Allow"
        }
    ]
}

Mitigation Strategies

  • Principle of Least Privilege: Assign only necessary permissions to each function.

    provider:
      [...]
      iam:
        role:
          statements:
            - Effect: 'Allow'
              Action:
                - 'dynamodb:PutItem'
                - 'dynamodb:Get*'
                - 'dynamodb:Scan*'
                - 'dynamodb:UpdateItem'
                - 'dynamodb:DeleteItem'
              Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
  • Use Separate Roles: Differentiate roles based on function requirements.


Insecure Secrets and Configuration Management

Storing sensitive information (e.g., API keys, database credentials) directly in serverless.yml or code can lead to exposure if repositories are compromised.

The recommended way to store environment variables in serverless.yml file from serverless.com (at the time of this writing) is to use the ssm or s3 providers, which allows to get the environment values from these sources at deployment time and configure the lambdas environment variables with the text clear of the values!

Therefore, anyone with permissions to read the lambdas configuration inside AWS will be able to access all these environment variables in clear text!

For example, the following example will use SSM to get an environment variable:

provider:
  environment:
    DB_PASSWORD: ${ssm:/aws/reference/secretsmanager/my-db-password~true}

And even if this prevents hardcoding the environment variable value in the serverless.yml file, the value will be obtained at deployment time and will be added in clear text inside the lambda environment variable.

The recommended way to store environment variables using serveless.com would be to store it in a AWS secret and just store the secret name in the environment variable and the lambda code should gather it.

Mitigation Strategies

  • Secrets Manager Integration: Use services like AWS Secrets Manager.

  • Encrypted Variables: Leverage Serverless Framework’s encryption features for sensitive data.

  • Access Controls: Restrict access to secrets based on roles.


Vulnerable Code and Dependencies

Outdated or insecure dependencies can introduce vulnerabilities, while improper input handling may lead to code injection attacks.

Mitigation Strategies

  • Dependency Management: Regularly update dependencies and scan for vulnerabilities.

    plugins:
      - serverless-webpack
      - serverless-plugin-snyk
  • Input Validation: Implement strict validation and sanitization of all inputs.

  • Code Reviews: Conduct thorough reviews to identify security flaws.

  • Static Analysis: Use tools to detect vulnerabilities in the codebase.


Inadequate Logging and Monitoring

Without proper logging and monitoring, malicious activities may go undetected, delaying incident response.

Mitigation Strategies

  • Centralized Logging: Aggregate logs using services like AWS CloudWatch or Datadog.

    plugins:
      - serverless-plugin-datadog
  • Enable Detailed Logging: Capture essential information without exposing sensitive data.

  • Set Up Alerts: Configure alerts for suspicious activities or anomalies.

  • Regular Monitoring: Continuously monitor logs and metrics for potential security incidents.


Insecure API Gateway Configurations

Open or improperly secured APIs can be exploited for unauthorized access, Denial of Service (DoS) attacks, or cross-site attacks.

Mitigation Strategies

  • Authentication and Authorization: Implement robust mechanisms like OAuth, API keys, or JWT.

    functions:
      hello:
        handler: handler.hello
        events:
          - http:
              path: hello
              method: get
              authorizer: aws_iam
  • Rate Limiting and Throttling: Prevent abuse by limiting request rates.

    provider:
      apiGateway:
        throttle:
          burstLimit: 200
          rateLimit: 100
  • Secure CORS Configuration: Restrict allowed origins, methods, and headers.

    functions:
      hello:
        handler: handler.hello
        events:
          - http:
              path: hello
              method: get
              cors:
                origin: https://yourdomain.com
                headers:
                  - Content-Type
  • Use Web Application Firewalls (WAF): Filter and monitor HTTP requests for malicious patterns.


Insufficient Function Isolation

Shared resources and inadequate isolation can lead to privilege escalations or unintended interactions between functions.

Mitigation Strategies

  • Isolate Functions: Assign distinct resources and IAM roles to ensure independent operation.

  • Resource Partitioning: Use separate databases or storage buckets for different functions.

  • Use VPCs: Deploy functions within Virtual Private Clouds for enhanced network isolation.

    provider:
      vpc:
        securityGroupIds:
          - sg-xxxxxxxx
        subnetIds:
          - subnet-xxxxxx
  • Limit Function Permissions: Ensure functions cannot access or interfere with each other’s resources unless explicitly required.


Inadequate Data Protection

Unencrypted data at rest or in transit can be exposed, leading to data breaches or tampering.

Mitigation Strategies

  • Encrypt Data at Rest: Utilize cloud service encryption features.

    resources:
      Resources:
        MyDynamoDBTable:
          Type: AWS::DynamoDB::Table
          Properties:
            SSESpecification:
              SSEEnabled: true
  • Encrypt Data in Transit: Use HTTPS/TLS for all data transmissions.

  • Secure API Communication: Enforce encryption protocols and validate certificates.

  • Manage Encryption Keys Securely: Use managed key services and rotate keys regularly.


Lack of Proper Error Handling

Detailed error messages can leak sensitive information about the infrastructure or codebase, while unhandled exceptions may lead to application crashes.

Mitigation Strategies

  • Generic Error Messages: Avoid exposing internal details in error responses.

    javascriptCopy code// Example in Node.js
    exports.hello = async (event) => {
      try {
        // Function logic
      } catch (error) {
        console.error(error);
        return {
          statusCode: 500,
          body: JSON.stringify({ message: 'Internal Server Error' }),
        };
      }
    };
  • Centralized Error Handling: Manage and sanitize errors consistently across all functions.

  • Monitor and Log Errors: Track and analyze errors internally without exposing details to end-users.


Insecure Deployment Practices

Exposed deployment configurations or unauthorized access to CI/CD pipelines can lead to malicious code deployments or misconfigurations.

Mitigation Strategies

  • Secure CI/CD Pipelines: Implement strict access controls, multi-factor authentication (MFA), and regular audits.

  • Store Configuration Securely: Keep deployment files free from hardcoded secrets and sensitive data.

  • Use Infrastructure as Code (IaC) Security Tools: Employ tools like Checkov or Terraform Sentinel to enforce security policies.

  • Immutable Deployments: Prevent unauthorized changes post-deployment by adopting immutable infrastructure practices.


Vulnerabilities in Plugins and Extensions

Using unvetted or malicious third-party plugins can introduce vulnerabilities into your serverless applications.

Mitigation Strategies

  • Vet Plugins Thoroughly: Assess the security of plugins before integration, favoring those from reputable sources.

  • Limit Plugin Usage: Use only necessary plugins to minimize the attack surface.

  • Monitor Plugin Updates: Keep plugins updated to benefit from security patches.

  • Isolate Plugin Environments: Run plugins in isolated environments to contain potential compromises.


Exposure of Sensitive Endpoints

Publicly accessible functions or unrestricted APIs can be exploited for unauthorized operations.

Mitigation Strategies

  • Restrict Function Access: Use VPCs, security groups, and firewall rules to limit access to trusted sources.

  • Implement Robust Authentication: Ensure all exposed endpoints require proper authentication and authorization.

  • Use API Gateways Securely: Configure API Gateways to enforce security policies, including input validation and rate limiting.

  • Disable Unused Endpoints: Regularly review and disable any endpoints that are no longer in use.


Excessive Permissions for Team Members and External Collaborators

Granting excessive permissions to team members and external collaborators can lead to unauthorized access, data breaches, and misuse of resources. This risk is heightened in environments where multiple individuals have varying levels of access, increasing the attack surface and potential for insider threats.

Mitigation Strategies

  • Principle of Least Privilege: Ensure that team members and collaborators have only the permissions necessary to perform their tasks.


Access Keys and License Keys Security

Access Keys and License Keys are critical credentials used to authenticate and authorize interactions with the Serverless Framework CLI.

  • License Keys: They are Unique identifiers required for authenticating access to Serverless Framework Version 4 which allows to login via CLI.

  • Access Keys: Credentials that allow the Serverless Framework CLI to authenticate with the Serverless Framework Dashboard. When login with serverless cli an access key will be generated and stored in the laptop. You can also set it as an environment variable named SERVERLESS_ACCESS_KEY.

Security Risks

  1. Exposure Through Code Repositories:

    • Hardcoding or accidentally committing Access Keys and License Keys to version control systems can lead to unauthorized access.

  2. Insecure Storage:

    • Storing keys in plaintext within environment variables or configuration files without proper encryption increases the likelihood of leakage.

  3. Improper Distribution:

    • Sharing keys through unsecured channels (e.g., email, chat) can result in interception by malicious actors.

  4. Lack of Rotation:

    • Not regularly rotating keys extends the exposure period if keys are compromised.

  5. Excessive Permissions:

    • Keys with broad permissions can be exploited to perform unauthorized actions across multiple resources.

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated