Hardening GitLab CI/CD: Secrets Detection, SAST & ECR Integration

Oshaba SamsonOshaba Samson
4 min read

DevOps is growing and changing every day, which also means new security risks can appear. Even if your cloud platform is well-protected, your CI/CD pipeline can still be a target. If the pipeline isn’t secure, attackers could find a way in or simple mistakes might go unnoticed and end up in production. That’s why it’s important to secure the entire process, not just the cloud.

Objectives

  • Sensitive information scanning using gitleaks

  • Static Application Security Testing (SAST)

  • ECR Integration

Requirement

The first we need to do is to

stages:
    - cache
    - test
    - build
    - deploy
    - upload_reports
    - deploy-test
    - deploy-prod

Install dependencies and Create Cache


create_cache:
    image: node:18-bullseye
    timeout: 2h
    stage: cache
    script:
        - yarn install
    cache:
        key:
            files:
                - yarn.lock
        paths:
            - node_modules/
            - yarn.lock
            - .yarn
        policy: pull-push
  • Scan for Secrets using gitleaks
gitleaks:
  stage: test
  image:
    name: zricethezav/gitleaks
    entrypoint: [""]
  script:
    - gitleaks detect --verbose --source .
  allow_failure: true
  • Scan for vulnerabilities using njsscan
njsscan:
  stage: test
  image: python
  before_script:
    - pip3 install --upgrade njsscan
  script:
    - njsscan --exit-warning .
  allow_failure: true
  • One security scan is not enough. One security scan tool might be good in one area and not in another area. We will be using another tool called semgrep

semgrep:
  stage: test
  image: returntocorp/semgrep
  variables:
    SEMGREP_RULES: p/javascript
  script:
    - semgrep ci
  allow_failure: true

When you run the pipeline. your pipeline is supposed to look like this

When you click on gitleaks you will see this result

You can see that it failed because it detected alot of secrets

  • If you click on njsscan

It detected a lot of vulnerabilities

  • When you click on semgrep

You will see the summary of the scan. The job failed because there are alot of security vulnerability on the code.

Docker and ECR Integration

To Create a repository in ecr

  • Login to you aws console

  • Click on Search

  • Type ECR

  • Select Elastic Container Registry

  • Click on Create

  • Type the name (juice-shop)

  • Scroll down and click on create

The ecr repository should look like this

Next is to generate access and secret keys in aws. if you dont know how to do that you can check out my previous post Mastering IAM in AWS: Creating Users and Roles Step-by-Step. Then create variables in gitlab settings. Create variables with this names

  • AWS_ACCESS_KEY_ID

  • AWS_SECRET_ACCESS_KEY

  • AWS_ACCOUNT_ID

You can check out my post on how to create variables https://devsecops-blog.hashnode.dev/how-to-securely-store-and-use-variables-in-gitlab-pipelines

Define the following variables at the top of your page


variables:
    IMAGE_NAME: $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/juice-shop
    IMAGE_TAG: $CI_COMMIT_SHA
    AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
    AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
    AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
    AWS_ACCOUNT_ID: $AWS_ACCOUNT_ID
    AWS_DEFAULT_REGION: us-east-1

Putting everything together

variables:
    IMAGE_NAME: $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/juice-shop
    IMAGE_TAG: $CI_COMMIT_SHA
    AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
    AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
    AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
    AWS_ACCOUNT_ID: $AWS_ACCOUNT_ID
    AWS_DEFAULT_REGION: us-east-1


stages:
    - cache
    - test
    - build


create_cache:
    image: node:18-bullseye
    timeout: 2h
    stage: cache
    script:
        - yarn install
    cache:
        key:
            files:
                - yarn.lock
        paths:
            - node_modules/
            - yarn.lock
            - .yarn
        policy: pull-push

gitleaks:
  stage: test
  image:
    name: zricethezav/gitleaks
    entrypoint: [""]
  script:
    - gitleaks detect --verbose --source .
  allow_failure: true

njsscan:
  stage: test
  image: python
  before_script:
    - pip3 install --upgrade njsscan
  script:
    - njsscan --exit-warning .
  allow_failure: true

semgrep:
  stage: test
  image: returntocorp/semgrep
  variables:
    SEMGREP_RULES: p/javascript
  script:
    - semgrep ci
  allow_failure: true

build_image_and_push:
    stage: build
    needs: ["create_cache", "gitleaks", "njsscan", "semgrep"]
    before_script:
        - aws ecr get-login-password | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
        # - echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
    script:
        - docker build -t $IMAGE_NAME:$IMAGE_TAG -t $IMAGE_NAME:latest  .
        - docker push $IMAGE_NAME:$IMAGE_TAG .
        - docker push $IMAGE_NAME:latest 
    tags:
      - ec2
      - shell

If your pipeline run successfully you should have something like this

0
Subscribe to my newsletter

Read articles from Oshaba Samson directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Oshaba Samson
Oshaba Samson

I am a software developer with 5 years + experience. I have working on web apps ecommerce, e-learning, hrm web applications and many others