Автор статьи: Рустем Галиев

IBM Senior DevOps Engineer & Integration Architect. Официальный DevOps ментор и коуч в IBM

Привет, Хабр!

Все больше компаний стремятся интегрировать безопасность в каждый этап разработки программного обеспечения. В контексте быстро развивающегося мира контейнеризации и облачных технологий, DevSecOps становится неотъемлемой частью создания безопасных и надежных приложений.

Одним из ключевых моментов при работе с контейнерами является безопасность образов. Amazon Elastic Container Registry (Amazon ECR) предоставляет мощный инструмент для хранения Docker-образов, но безопасность этих образов играет критическую роль. В этой статье мы исследуем процесс сканирования образов на безопасность перед их отправкой в Amazon ECR, раскрывая методы и инструменты, которые помогают обеспечить непрерывную безопасность в DevSecOps-окружении.

Amazon Elastic Container Registry (Amazon ECR) — это управляемый сервис хранения контейнеров от Amazon Web Services (AWS). Amazon ECR предоставляет безопасное и масштабируемое хранилище для Docker-образов, которые могут быть использованы в сервисе AWS Elastic Container Service (ECS), Kubernetes на AWS (Amazon EKS) или самостоятельно в других инструментах управления контейнерами.

Безопасность образов контейнеров играет критическую роль в DevSecOps. Образы контейнеров представляют собой основу для развертывания приложений в инфраструктуре, и даже незначительные уязвимости или ошибки в них могут привести к серьезным угрозам безопасности.

Сканирование образов на безопасность — важная практика, которая позволяет выявлять уязвимости, недостатки конфигурации и потенциальные угрозы в образах контейнеров еще до их развертывания. Это обеспечивает возможность предотвращения инцидентов безопасности на ранних этапах разработки и эксплуатации приложений.

Процесс сканирования образов на безопасность включает в себя несколько ключевых аспектов:

  • Поиск уязвимостей: Использование специализированных инструментов для сканирования образов на предмет известных уязвимостей, включая устаревшие библиотеки, известные уязвимости безопасности и прочие уязвимости, которые могут быть использованы злоумышленниками.

  • Проверка конфигурации: Анализ конфигурации образа на предмет соответствия лучшим практикам безопасности, включая правильность настройки сетевых параметров, доступность лишь необходимых сервисов и минимизацию доступа к привилегиям.

  • Интеграция с процессами CI/CD: Автоматизация сканирования образов в рамках цепочек Continuous Integration и Continuous Deployment (CI/CD) для обеспечения непрерывной проверки безопасности образов на всех этапах разработки и развертывания.

  • Управление угрозами: Оценка и приоритизация обнаруженных уязвимостей, а также принятие мер для устранения или уменьшения их воздействия на безопасность приложения.

Инструменты для сканирования образов на безопасность, такие как Clair, Anchore, Twistlock, Trivy и другие, предоставляют возможность автоматического анализа контейнерных образов на предмет уязвимостей и неправильной конфигурации. Их интеграция в пайплайны CI/CD позволяет обеспечить непрерывную безопасность приложений, начиная с ранних этапов разработки и до их эксплуатации в продакшне.

Этот процесс сканирования образов на безопасность становится ключевым элементом стратегии DevSecOps и гарантирует, что безопасность интегрируется в каждый этап жизненного цикла приложения.

Давайте приступим. Для пререквизитов нам понадобится аккаунт в aws и aws cli

Создадим ECR репозиторий:

aws ecr create-repository --repository-name scan-repo

В командной строке применим конфигурацию сканирования к созданному репозиторию:

aws ecr put-image-scanning-configuration </span>

--repository-name scan-repo </span>

--image-scanning-configuration scanOnPush=true

Эта конфигурация устанавливает для scanOnPush значение true для репозитория контейнеров. Это означает, что каждый раз, когда вы отправляете новый образ контейнера, он будет генерировать отчет об уязвимостях.

Напишем небольшой bash скрипт, который предоставит необходимые нам ресурсы:

echo "Script to create required resources: key pair, VPC, internet gateway, subnet, security group, etc."

KEY_NAME=$username-key

`aws ec2 create-key-pair --key-name $KEY_NAME --key-type rsa --key-format pem --region us-east-1  --query "KeyMaterial" --output text > $KEY_NAME.pem`

chmod 400 $KEY_NAME.pem

VPC_ID=`aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query Vpc.VpcId --region us-east-1 --output text`

SUBNET_ID=`aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.1.0/24 --query Subnet.SubnetId --output text --region us-east-1` 

INTERNET_GATEWAY_ID=`aws ec2 create-internet-gateway --query InternetGateway.InternetGatewayId --output text`

aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $INTERNET_GATEWAY_ID

ROUTE_TABLE_ID=`aws ec2 create-route-table --vpc-id $VPC_ID --query RouteTable.RouteTableId --output text`

aws ec2 create-route --route-table-id $ROUTE_TABLE_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $INTERNET_GATEWAY_ID

aws ec2 associate-route-table --subnet-id $SUBNET_ID --route-table-id $ROUTE_TABLE_ID

SECURITY_GROUP_NAME=$username-security-group

SECURITY_GROUP=`aws ec2 create-security-group --vpc-id $VPC_ID  --group-name $SECURITY_GROUP_NAME --description "My $SECURYT_GROUP_NAME security group" --region us-east-1 --output text`

aws ec2 authorize-security-group-ingress --group-id $SECURITY_GROUP --protocol tcp  --port 22 --cidr 0.0.0.0/0 --region us-east-1

aws ec2 authorize-security-group-ingress --group-id $SECURITY_GROUP --protocol tcp  --port 80 --cidr 0.0.0.0/0 --region us-east-1

BUCKET_NAME=$username

aws s3api create-bucket --bucket $BUCKET_NAME

aws iam create-role --role-name AWSCookbookLambdaRole --assume-role-policy-document file://policy_template.json

echo "All resources required were provisioned."

echo "-------------------------------------------------"

echo "Resources created for this lab are: "
echo "      VPC:                $VPC_ID"
echo "      KEY:                $KEY_NAME"
echo "      Subnet:             $SUBNET_ID"
echo "      Key:                $KEY_NAME"
echo "      Security Group:     $SECURITY_GROUP"

Напишем и запустим bash-скрипт для создание ec2 инстанса(конечно можно и терраформом, на bash писать интереснее)

echo "Script to create an instance."

KEY_NAME=$username-key

INSTANCE_ID_1=`aws ec2 run-instances --image-id ami-09d3b3274b6c5d4aa --instance-type t2.micro --key-name $KEY_NAME --security-group-ids $SECURITY_GROUP --subnet-id $SUBNET_ID --associate-public-ip-address --count 1 --query 'Instances[0].InstanceId' --output text --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ec2-instance-1}]' --user-data file://userdata.sh`

sleep 5

aws iam create-role --role-name ec2s3access --assume-role-policy-document file://trust_policy.json
aws iam attach-role-policy --role-name ec2s3access --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
aws iam attach-role-policy --role-name ec2s3access --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
aws iam attach-role-policy --role-name ec2s3access --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam list-attached-role-policies --role-name ec2s3access
aws iam create-instance-profile --instance-profile-name ec2s3accessprofile
aws iam wait instance-profile-exists --instance-profile-name ec2s3accessprofile
sleep 10
aws iam add-role-to-instance-profile --role-name ec2s3access --instance-profile-name ec2s3accessprofile
sleep 120
echo "Done, Your instance will be available shortly"

Теперь мы подключимся к инстансу, чтобы создать образ лямбда-контейнера и отправить его в ECR. Нужно получить IP-адреса созданного вами инстанса EC2 и установить их в качестве переменных. Этот скрипт сделает это за нас.

echo "Setting Variables, One moment..."

INSTANCE_IP_1=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID_1 --query Reservations[].Instances[].{Address:PublicIpAddress} --output text)

echo "Associating EC2 instance with the S3 Access Profile..."

aws ec2 associate-iam-instance-profile --instance-id $INSTANCE_ID_1 --iam-instance-profile Name=ec2s3accessprofile

echo "Variables are set!"

Мы сохраняем идентификатор учетной записи AWS в переменной и копируем его в ваш инстанс EC2:

echo "AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID" > .env

scp -o StrictHostKeyChecking=no -i $username-key.pem .env ec2-user@$INSTANCE_IP_1:~/

Теперь сами подключимся

ssh -o StrictHostKeyChecking=no -i $username-key.pem ec2-user@$INSTANCE_IP_1

Теперь, когда мы подключены к нашему инстансу EC2, это можно считать нашей средой разработки. Мы устанавливаем регион в нашем экземпляре EC2, чтобы AWS CLI мог его инициализировать:

export AWS_DEFAULT_REGION=us-east-1

Устанавливаем переменные среды:

source .env

Получаем данные для входа в ECR и в Docker:

aws ecr get-login-password | docker login --username AWS \
--password-stdin $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com

Вместо того, чтобы создавать новый образ контейнера из файла Dockerfile, на этот раз мы собираемся запуллить старый образ контейнера NGINX (версия 1.14.1 является более старой версией NGINX и действительно содержит уязвимости безопасности, которые были исправлены в новых версиях, поэтому разумно использовать в целях тестирования):

docker pull nginx:1.14.1

Данные для входа в Docker:

aws ecr get-login-password | docker login --username AWS \
--password-stdin $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com

Применяем тег к изображению, чтобы можно было отправить его в репозиторий ECR:

docker tag nginx:1.14.1 \
$AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/scan-repo:old

Пушим

docker push \
> $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/scan-repo:old

Вскоре после завершения отправки мы можем просмотреть результаты сканирования безопасности изображения в формате JSON:

aws ecr describe-image-scan-findings \
> --repository-name scan-repo --image-id imageTag=old | head -20

Уязвимости системы безопасности классифицируются по степени серьезности и им присваивается номер CVE. CVE расшифровывается как Common Vulnerabilities and Exposures и представляет собой глоссарий, поддерживаемый консорциумом и классифицирующий уязвимости. Оценка CVE часто используется для определения приоритета безопасности уязвимостей. Эта уязвимость имеет КРИТИЧЕСКИЙ уровень и, следовательно, будет иметь высший приоритет. В этом случае решением будет обновить версию NGINX.

Статья подготовлена в рамках онлайн-курса «Внедрение и работа в DevSecOps». Записывайтесь на бесплатные открытые уроки на странице курса.

Комментарии (2)


  1. ilyakruchinin
    29.11.2023 02:22
    +2

    Зачем создавать VPC, плясать с бубном и SSH-ключами (ужас, в 2023 при наличии Session Manager) и запускать EC2-инстанс?
    Для работы с ECR ничего этого не нужно, ни VPC, ни маршруты, ни S3, ни EC2.

    Что мешает локально (со своей машины) создать репозитарий с конфигурацией сканирования, сделать docker pull, авторизоваться в ECR и сделать docker push (итого 5 строк)?
    Статью можно уместить в 1 абзац.
    Какую-то антирекламу курса по DevSecOps сделали.


  1. thunderspb
    29.11.2023 02:22

    Опять вода какая-то... Правильно заметили про пару строк....

    Опять перечислены тулы для скана, а в итоге всё свелось к scan_on_push.

    Я б тоже не пошёл на такие курсы...