Конвейеры CI/CD облегчают работу разработчиков и позволяют им быстрее доводить изменения до конечных пользователей. Однако они также являются частью систем обеспечения соответствия требованиям, таких как SOC 2, которые требуют тщательного проектирования для соблюдения определенных мер контроля.
Архитектура учетных записей AWS
Не рекомендуется размещать все свои среды, такие как тестовая и производственная, в одной учетной записи AWS; вместо этого следует использовать архитектуру AWS с несколькими учетными записями.
Каждая из ваших сред - dev, staging, UAT, prod - должна находиться в отдельной учетной записи AWS, а не в одной общей. Таким образом, вы сможете обеспечить четкие логические средства контроля доступа (CC6.1).
Как только у каждой среды появится своя учетная запись, возникает естественный вопрос: где должен находиться ваш репозиторий ECR? Следует ли размещать по одному в каждой учетной записи среды или централизовать его в одной учетной записи, из которой все среды будут извлекать образы?
Архитектура репозитория ECR
Вы можете разместить репозиторий ECR в учетной записи производственной среды, но в идеале следует создать отдельную учетную запись AWS для общих инструментов и разместить репозиторий ECR именно там. Ваш конвейер должен иметь только доступ на отправку (push) в этот репозиторий, ограниченный областью действия общей учетной записи.
Затем каждой учетной записи среды (dev, staging и prod) потребуются межучетные разрешения на извлечение (но не на отправку) образов из этого общего репозитория. В общей учетной записи создайте роль IAM, которая проходит аутентификацию через OIDC и может отправлять данные в соответствующие репозитории ECR. Эта роль не нуждается в доступе на извлечение.
Пример политики разрешений для этой роли выглядит следующим образом:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowECRAuth", "Effect": "Allow", "Action": "ecr:GetAuthorizationToken", "Resource": "*" }, { "Sid": "AllowPushToScopedRepos", "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:PutImage", "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload" ], "Resource": [ "arn:aws:ecr:<REGION>:<COMMON_ACCOUNT_ID>:repository/myapp-*" ] } ]}
ecr:GetAuthorizationToken должен оставаться привязанным ко всем ресурсам, поскольку AWS не поддерживает ограничение этого конкретного действия ARN репозитория. Именно так выдается токен входа в ECR. Все остальное привязано к конкретному шаблону именования репозиториев, а не к простому подстановочному знаку.
Приведённая ниже политика доверия фактически определяет, кто может принять на себя эту роль. Она точно определяет, для какого репозитория и ветки GitHub разрешена аутентификация через OIDC. Без такого ограничения любой рабочий процесс в вашей организации GitHub потенциально мог бы принять на себя эту роль.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<COMMON_ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" }, "StringLike": { "token.actions.githubusercontent.com:sub": "repo:<GITHUB_ORG>/<GITHUB_REPO>:ref:refs/heads/main" } } } ]}
Подусловие - это то, что фактически обеспечивает ограничение доступа. Оно гарантирует, что только рабочие процессы, запущенные на главной ветке этого конкретного репозитория, могут принимать эту роль. Вы можете изменить эту роль позже или создать новые по мере добавления дополнительных репозиториев GitHub и соответствующих им репозиториев ECR.
Наконец, убедитесь, что в вашем репозитории ECR включена опция «сканирование при запуске» (scan on push). Это гарантирует, что каждый образ будет автоматически сканироваться на наличие известных уязвимостей сразу же после запуска, а не по периодическому расписанию. Это является прямым доказательством соответствия требованиям CC7.1 (управление уязвимостями).
Политики жизненного цикла ECR
Настройте политики жизненного цикла, чтобы ваш репозиторий ECR не разрастался бесконечно и не приводил к росту затрат на хранение. Однако не применяйте одно универсальное правило, поскольку образы без тегов, сборки для разработчиков и продвинутые релизы имеют разные требования к срокам хранения.
Удаляйте образы без тегов через несколько дней; они не представляют постоянной ценности. Для образов с тегом «dev» определяйте количество образов для хранения в соответствии с вашим фактическим циклом разработки, а не устанавливайте фиксированный временной интервал. Если ваша команда проходит через множество сборок, прежде чем остановиться на одной для продвижения, сохраняйте большее количество (500-1 000); если ваши циклы разработки короткие, подойдет меньшее количество (100-200). Для образов с тегами «staging» и «prod» сохраняйте последние 100-200 релизов независимо от срока хранения, так как они служат вашим журналом аудита.
{ "rules": [ { "rulePriority": 1, "selection": { "tagStatus": "untagged", "countType": "sinceImagePushed", "countUnit": "days", "countNumber": 3 }, "action": { "type": "expire" } }, { "rulePriority": 2, "selection": { "tagStatus": "tagged", "tagPrefixList": ["dev-"], "countType": "imageCountMoreThan", "countNumber": 200 }, "action": { "type": "expire" } }, { "rulePriority": 3, "selection": { "tagStatus": "tagged", "tagPatternList": ["*.*.*"], "countType": "imageCountMoreThan", "countNumber": 200 }, "action": { "type": "expire" } } ]}
ECR оценивает правила в порядке приоритета, и срок хранения каждого образа истекает по первому правилу, которое ему соответствует, поэтому порядок и префиксы тегов имеют значение. Настройте префикс «dev-» и числа в соответствии с вашими собственными соглашениями о тегировании и ритмом выпуска версий.
Теперь вы можете спроектировать свой конвейер с учётом особенностей работы вашей команды. Вот один из примеров, в котором предполагается наличие сред dev, staging и prod.
Пример архитектуры конвейера CI/CD
Когда пул-реквест сливается в основную ветку (main), конвейер выполняет развертывание в среду dev. Используйте тегирование образов, например по схеме semver, чтобы каждая сборка для dev получала префикс «dev-», версию патча и последние семь символов SHA-хеша коммита. Теги образов для dev в ECR будут выглядеть следующим образом:
dev-0.2.1-a3f9c2edev-0.2.2-8d4b17f
Каждый из этих тегов также должен быть отмечен в GitHub, чтобы вы могли показать аудитору, какой именно коммит работал в данной среде в данный момент времени.
Как только вы будете удовлетворены версией dev и захотите перенести её в среду staging, используйте триггер ручного рабочего процесса, который перемаркирует этот конкретный образ dev, передавая целевую второстепенную версию в качестве параметра (SHA-хэш коммита не требуется). Например, dev-0.2.2-8d4b17f получает второй тег - 0.3.0. Это тот же самый образ с двумя тегами, а не новая сборка, и в этом суть: вы переносите именно тот артефакт, который тестировался в dev, а не собираете его заново.
Если вы обнаружите, что для dev, staging и prod требуются действительно разные образы, это обычно свидетельствует о проблеме проектирования в другой части конвейера. Лучшим решением будет параметризация всего, что отличается между средами (конфигурация, переменные среды или флаги функций), а не сборка отдельных образов для каждой среды.
Допустим, на стадии staging запускаются интеграционные тесты, нагрузочные тесты и всё остальное, что входит в ваш конвейер, и вы готовы перенести образ в prod. Используйте другой триггер ручного рабочего процесса, в идеале с обязательным этапом утверждения, который перемаркирует тот же образ с увеличением версии. Например, версия 0.3.0 получает третий тег - 1.0.0. На данный момент один и тот же образ имеет три тега: dev-0.2.2-8d4b17f, 0.3.0 и 1.0.0.
Теперь вы запускаете в производственной среде тот же артефакт, который тестировался в средах разработки и промежуточного тестирования. Его также можно отследить до точной версии кода, запущенной на GitHub, что соответствует требованию CC8.1 (управление изменениями).
Заключение
Здесь рассмотрен типичный паттерн CI/CD, а не универсальный шаблон. Структура вашей учетной записи, схема тегирования и правила жизненного цикла должны отражать реальный рабочий процесс вашей команды. Сравните это с вашим собственным объемом и средствами контроля SOC 2 и скорректируйте там, где ваш рабочий процесс действительно отличается.
Имейте в виду, что это лишь часть SOC 2 на AWS, касающаяся CI/CD. Для достижения полного соответствия требованиям SOC 2 на AWS необходимо учитывать дополнительные детали, такие как GuardDuty, Security Hub и другие инструменты.
Читайте также
- Чему AWS научилась о зональных сбоях, запустив Kubernetes в миллионах кластеров
- AWS размещает «охранителя» на базе ИИ в очереди слияния
- Сократить использование токенов ИИ на 96 %? Вот как это удается с помощью AWS Strands Agents.
Подписывайтесь на наш канал в Телеграм
⚡ Подписаться