# 컨테이너 배포 파이프라인에서의 보안 테스트 통합 ## 개요 이 워크숍에서는 AWS 개발 도구와 오픈 소스 프로젝트를 활용하여 자동화된 보안 테스트를 CI/CD 파이프라인에 통합하는 방법을 배웁니다. 보안 중심 릴리스 제어를 AWS CodePipeline에 통합하기 위한 다양한 패턴에 대해 학습합니다. 또한 피드백 루프를 추가하고 컨테이너 기반 애플리케이션에서 일반적인 보안 취약성을 수정하는 방법을 배우게 됩니다. :::info * 레벨 : 고급 * 소요시간 : 2~3시간 * 전제 조건 : AWS 계정, 관리자 IAM 사용자 * CSF 기능 : Prevent, Detect * CAF 구성품 : Preventative, Detective * AWS 서비스 : Amazon CloudWatch , AWS CodeCommit , AWS CodeBuild , AWS CodePipeline , Amazon ECR , AWS Lambda 및 AWS Security Hub * 오픈 소스 프로젝트 : Hadolint , Trufflehog 및 Anchore ::: ## 시나리오 귀사는 소프트웨어 개발 수명 주기의 모든 부분에 보안을 내장하여 중요한 애플리케이션의 보안을 개선하기 위한 노력의 일환으로 새로운 DevSecOps 이니셔티브를 막 시작했습니다. 귀하는 보안 테스트를 컨테이너 이미지를 빌드하고 릴리스하기 위한 기본 파이프라인에 통합하는 임무를 맡은 DevOps 팀의 일원입니다. 초기 작업에는 Dockerfile 린트 추가, 보안 정보 및 취약성 스캔이 포함됩니다. 요구 사항이 얼마나 잘 충족되는지에 따라 상용 제품으로 이동할 가능성이 있는 오픈 소스 프로젝트를 평가하고 사용하기로 결정했습니다. ## Architecture 이 워크샵에서는 풀 요청에서 트리거되고 컨테이너 이미지를 빌드하고 Amazon ECR 리포지토리로 푸시하는 기본 CI/CD 파이프라인으로 시작합니다. 최신 스프린트에서 작업을 수행하면 아래와 같이 CI/CD 파이프라인이 완성됩니다. 여기에는 Dockerfile을 린트하고, 보안 정보를 스캔하고, AWS Security Hub와의 통합을 포함하여 취약점을 스캔하기 위한 AWS CodePipeline 내의 단계가 포함됩니다. 또한 Amazon CloudWatch 이벤트 규칙과 AWS Lambda 함수의 조합을 사용하여 보안 테스트의 각 단계에 대한 피드백 루프를 생성합니다. 이를 통해 개발자는 코드를 신속하게 수정하고 반복하여 더 빠르고 안전하게 전달할 수 있습니다. ![](https://i.imgur.com/KPmviXa.png) --- ## 모듈 0 : 사전 준비 **소요시간**: 30분 첫 번째 모듈에서는 초기 파이프라인을 구성하고 이 워크샵의 뒷부분에서 파이프라인에 통합할 Anchore 서비스를 설정합니다. 이 모듈을 사용하려면 파이프라인 및 Anchore 서비스 생성을 자동화 하는 AWS CloudFormation 템플릿 을 실행해야 합니다. 그런 다음 각 단계를 살펴보고 보안 테스트를 수동으로 구성합니다. ### 환경 * Region: US-East-2 (Ohio) ### Role 확인 * AWSServiceRoleForECS ### Workshop 배포 CloudFormation Workshop 구성 파일을 CloudFormation 을 이용하여 배포합니다. <i class="octicon octicon-link">**클릭**</i> [DevSecOps](https://d19k26wivhxcqg.cloudfront.net/imd/devsecops/cicd/DevSecOps.yml) 소요시간: 약 15분 --- :::spoiler 만약, 위의 CloudFormation 이 실패 한다면, 1. [AnchoreVpcStack](https://d19k26wivhxcqg.cloudfront.net/imd/devsecops/cicd/01+anchore-vpc.yml) (약5분) 1. [AnchoreStack](https://d19k26wivhxcqg.cloudfront.net/imd/devsecops/cicd/02+anchore-fargate.yml) (약10분) 1. [InitialPipeline](https://d19k26wivhxcqg.cloudfront.net/imd/devsecops/cicd/03+pipeline-setup.yml) (약5분) :::danger :fire: **주의** : 한 번에 하나씩 배포를 완료 후에 다음 스텍을 배포해야만 합니다. ::: --- ### Fargate 확인 * AnchoreStack 배포후에 Fargate가 정상적으로 동작중인지 확인 * EC2 > 로드 밸런싱 > 로드밸런서 * 만들어진 로드밸런서 [devsecop-LB-xxx]를 선택합니다. * 상세 정보에 있는 DNS 이름을 복사하여 브라우저에서 확인합니다. * ![실행결과1](https://i.imgur.com/BDiASVG.png) ### Cloud9 브라우저만으로 코드를 작성, 실행 및 디버그 할 수 있는 클라우드 기반 통합 개발 환경(IDE)인 AWS Cloud9내에서 AWS 명령줄 인터페이스(CLI)를 사용하여 워크숍의 대부분을 수행할 것입니다. 1. AWS Cloud9 콘솔 (us-east-2)을 엽니다. 1. container-devsecops-wksp-ide 환경에서 Open IDE 를 클릭 합니다. 그러면 새 탭의 IDE로 이동합니다. 이 탭을 항상 열어 두십시오. ### Repository 복제 git 자격 증명을 설정하고 파이프라인에 대한 모든 구성이 포함된 리포지토리를 복제합니다. ```console git config --global credential.helper '!aws codecommit credential-helper $@' git config --global credential.UseHttpPath true git clone https://git-codecommit.us-east-2.amazonaws.com/v1/repos/container-devsecops-wksp-config configurations git clone https://git-codecommit.us-east-2.amazonaws.com/v1/repos/container-devsecops-wksp-app sample-application ``` ### AWS Security Hub 활성화 AWS Security Hub를 사용하여 컨테이너 이미지 취약성을 관리하게 됩니다. ``` aws securityhub enable-security-hub ``` ### Pipeline Architecture AWS CodePipeline으로 이동하여 현재 파이프라인을 볼 수 있습니다 . 모든 단계가 있지만 제대로 구성되지 않았습니다. 다음은 파이프라인의 현재 아키텍처입니다. ![](https://i.imgur.com/uIjPggS.png) --- ## 모듈 1 : Dockerfile Linting **소요시간**: 5분 이제 초기 파이프라인 설정이 완료되었으므로 보안 테스트 통합을 시작할 때입니다. 추가할 첫 번째 단계는 모범 사례 Docker 이미지를 빌드하는 데 도움이 되는 Dockerfiles Linting을 수행하는 것입니다. Linting의 경우 Dockerfile을 Linting하고 인라인 bash를 검증하는 인기 있는 오픈 소스 프로젝트인 [Hadolint](https://github.com/hadolint/hadolint)를 활용합니다. linter는 Dockerfile을 AST로 구문 분석하고 AST 위에 규칙을 수행합니다. 규칙이 모든 보안에만 적용되는 것은 아니지만 모범 사례 전반에 걸쳐 잘 적용됩니다 * CodeBuild의 프로젝트를 확인하려면 [클릭](https://us-east-2.console.aws.amazon.com/codesuite/codebuild/projects/container-devsecops-wksp-build-dockerfile/details?region=us-east-2)하세요. ### Build spec 파일 만들기 각 CodeBuild 프로젝트에는 CodeBuild가 빌드를 실행하는데 사용하는 YAML 형식의 빌드 명령 및 관련 설정 모음인 빌드 사양(Build spec) 파일이 포함되어 있습니다. Hadolint를 사용하여 Dockerfile linting을 수행하기 위한 명령을 정의하는 파일입니다. 1. Cloud9 IDE 탭을 클릭합니다. 1. 왼쪽 파일 트리에서 **configurations** 폴더를 확장하고 **buildspec_dockerfile.yml**을 엽니다. 1. 아래 YAML 코드를 검토하고 파일에 붙여넣고 저장합니다. ```yaml version: 0.2 phases: pre_build: commands: - echo "Copying hadolint.yml to the application directory" - cp hadolint.yml $CODEBUILD_SRC_DIR_AppSource/hadolint.yml - echo "Switching to the application directory" - cd $CODEBUILD_SRC_DIR_AppSource - echo "Pulling the hadolint docker image" - docker pull public.ecr.aws/x8q1e6c8/hadolint/hadolint:v1.16.2 - docker image tag public.ecr.aws/x8q1e6c8/hadolint/hadolint:v1.16.2 hadolint/hadolint:v1.16.2 build: commands: - echo "Build started on $(date)" - echo "Scanning with Hadolint..." - result=`docker run --rm -i -v ${PWD}/hadolint.yml:/.hadolint.yaml hadolint/hadolint:v1.16.2 hadolint -f json - < Dockerfile` post_build: commands: - echo "Lint Results:" - echo $result | jq . - aws ssm put-parameter --name "codebuild-dockerfile-results" --type "String" --value "$result" --overwrite - echo Build completed on `date` ``` ### Hadolint 구성 추가 Hadolint를 사용할 때 필요하지 않은 특정 규칙을 무시하고 신뢰할 수 있는 레지스트리를 지정하도록 구성 파일을 선택적으로 지정할 수 있습니다. [Hadolint github 프로젝트](https://github.com/hadolint/hadolint)에서 아래로 스크롤하여 모든 현재 규칙을 볼 수 있습니다. 1. 왼쪽 파일 트리에서 **configurations** 폴더를 확장하고 **hadolint.yml** 을 엽니다. 1. 아래에 YAML을 붙여넣고 파일을 저장합니다. ```yaml ignored: - DL3000 - DL3025 trustedRegistries: - examplecorp.com ``` ### Pipeline Architecture 다음은 파이프라인의 현재 아키텍처입니다. ![](https://i.imgur.com/76N28Gy.png) --- ## 모듈 2 : Secret 스캐닝 **소요시간**: 5분 다음으로 코드 전체에서 입력된 암호를 식별하기 위한 단계를 설정해야 합니다. 이 단계에서는 리포지토리에서 실수로 커밋된 암호나 보안 정보를 찾기 위한 인기있는 오픈 소스 프로젝트인 [trufflehog](https://github.com/dxa4481/truffleHog)를 활용할 것 입니다. 기본적으로 git 리포지토리를 통해 암호를 검색하고 커밋 기록과 브랜치를 깊이 파헤칩니다. 엔트로피 검사와 높은 신호 정규식 검사를 실행하여 보안 정보를 식별합니다. ### Build spec 파일 만들기 1. Cloud9 IDE 탭을 클릭합니다. 1. 왼쪽 파일 트리에서 **configurations** 폴더를 확장하고 **buildspec_secrets.yml** 을 엽니다. 1. 아래 YAML 코드를 검토하고 파일에 붙여넣고 저장합니다. ```bash version: 0.2 phases: pre_build: commands: - echo "Setting CodeCommit Credentials" - git config --global credential.helper '!aws codecommit credential-helper $@' - git config --global credential.UseHttpPath true - echo "Copying secrets_config.json to the application directory" - cp secrets_config.json $CODEBUILD_SRC_DIR_AppSource/secrets_config.json - echo "Switching to the application directory" - echo "Installing truffleHog" - which pip3 && pip3 --version - which python3 && python3 --version - pip3 install 'truffleHog>=2.1.0,<3.0' build: commands: - echo "Build started on $(date)" - echo "Scanning with truffleHog..." - trufflehog --regex --rules secrets_config.json --entropy=False "$APP_REPO_URL" post_build: commands: - echo "Build completed on $(date)" ``` ### trufflehog 정규식 구성 추가 trufflehog를 사용할 때 사용자 정의 정규식 검사가 포함된 구성 파일을 선택적으로 지정할 수 있습니다. 1. 왼쪽 파일 트리에서 **configurations** 폴더를 확장하고 **secrets_config.json**을 엽니다. 1. 아래에 JSON을 붙여넣고 파일을 저장합니다. ```json { "Slack Token": "(xox[p|b|o|a]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32})", "RSA private key": "-----BEGIN RSA PRIVATE KEY-----", "SSH (OPENSSH) private key": "-----BEGIN OPENSSH PRIVATE KEY-----", "SSH (DSA) private key": "-----BEGIN DSA PRIVATE KEY-----", "SSH (EC) private key": "-----BEGIN EC PRIVATE KEY-----", "PGP private key block": "-----BEGIN PGP PRIVATE KEY BLOCK-----", "Facebook Oauth": "[f|F][a|A][c|C][e|E][b|B][o|O][o|O][k|K].*['|\"][0-9a-f]{32}['|\"]", "Twitter Oauth": "[t|T][w|W][i|I][t|T][t|T][e|E][r|R].*['|\"][0-9a-zA-Z]{35,44}['|\"]", "GitHub": "[g|G][i|I][t|T][h|H][u|U][b|B].*['|\"][0-9a-zA-Z]{35,40}['|\"]", "Google Oauth": "(\"client_secret\":\"[a-zA-Z0-9-_]{24}\")", "AWS API Key": "AKIA[0-9A-Z]{16}", "Heroku API Key": "[h|H][e|E][r|R][o|O][k|K][u|U].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}", "Generic Secret": "[s|S][e|E][c|C][r|R][e|E][t|T].*['|\"][0-9a-zA-Z]{32,45}['|\"]", "Generic API Key": "[a|A][p|P][i|I][_]?[k|K][e|E][y|Y].*['|\"][0-9a-zA-Z]{32,45}['|\"]", "Slack Webhook": "https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}", "Google (GCP) Service-account": "\"type\": \"service_account\"", "Twilio API Key": "SK[a-z0-9]{32}", "Password in URL": "[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}[\"'\\s]" } ``` ### Pipeline Architecture 다음은 파이프라인의 현재 아키텍처입니다. ![](https://i.imgur.com/yUYKCKh.png) --- ## 모듈 3 : 취약점 검색 **소요시간**: 5분 이번 모듈에서 추가할 마지막 단계는 컨테이너 이미지의 취약점을 식별하는 것입니다. 이 단계 에서는 널리 사용 되는 오픈 소스 컨테이너 규정 준수 플랫폼인 [Anchore](https://anchore.com/opensource/)를 사용 합니다. 이 서비스는 다양한 유효성 검사를 수행할 수 있지만 주로 CVE(Common Vulnerabilities and Exposures)에 대한 이미지를 확인하는데 사용합니다. ### Build spec 파일 만들기 1. Cloud9 IDE 탭을 클릭합니다. 1. 왼쪽 파일 트리에서 **configurations** 폴더를 확장하고 **buildspec_vuln.yml** 을 엽니다. 1. 아래 YAML 코드를 검토하고 파일에 붙여넣고 저장합니다. ```yaml version: 0.2 phases: pre_build: commands: - apt-get update && apt-get install -y python-dev jq - docker pull public.ecr.aws/x8q1e6c8/anchore/engine-cli:v0.8.2 - docker image tag public.ecr.aws/x8q1e6c8/anchore/engine-cli:v0.8.2 anchore/engine-cli:v0.8.2 - curl https://bootstrap.pypa.io/pip/3.4/get-pip.py -o get-pip.py - python3 get-pip.py - pip3 install awscli - $(aws ecr get-login --no-include-email) - ANCHORE_CMD="docker run -e ANCHORE_CLI_URL=$ANCHORE_CLI_URL -e ANCHORE_CLI_USER=$ANCHORE_CLI_USER -e ANCHORE_CLI_PASS=$ANCHORE_CLI_PASS anchore/engine-cli:v0.8.2 anchore-cli" - $ANCHORE_CMD registry add $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com awsauto awsauto --registry-type=awsecr || return 0 build: commands: - IMAGE=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME - docker build $CODEBUILD_SRC_DIR_AppSource -t $IMAGE - docker push $IMAGE post_build: commands: - $ANCHORE_CMD image add $IMAGE - while [ $($ANCHORE_CMD --json image get $IMAGE | jq -r '.[0].analysis_status') != "analyzed" ]; do sleep 1; done - $ANCHORE_CMD --json image vuln $IMAGE all > scan_results.json - jq -c --arg image $IMAGE --arg arn $IMAGE_ARN '. + {image_id:$image, image_arn:$arn}' scan_results.json >> tmp.json - mv tmp.json scan_results.json - aws lambda invoke --function-name $FUNCTION_ARN --invocation-type RequestResponse --payload file://scan_results.json outfile - cat scan_results.json - cat scan_results.json | jq -r --arg threshold $FAIL_WHEN '.vulnerabilities[] | select(.severity==$threshold)' - if cat scan_results.json | jq -r --arg threshold $FAIL_WHEN '.vulnerabilities[] | (.severity==$threshold)' | grep -q true; then echo "Vulnerabilties Found" && exit 1; fi ``` ### 모든 구성 변경 커밋 Configuration 리포지토리에서 여러 파일을 변경했으므로 파이프라인이 올바른 파일을 가져오도록 이러한 변경 사항을 커밋해야 합니다. ```bash cd /home/ec2-user/environment/configurations git add . git commit -m "Updated Build Spec files and configurations." git push -u origin master ``` ### Pipeline Architecture 다음은 파이프라인의 현재 아키텍처입니다. ![](https://i.imgur.com/cqEJy2V.png) --- ## 모듈 4 : 파이프라인 테스트 **소요시간**: 5분 여러 유형의 보안 테스트를 파이프라인에 통합했으므로 이제 테스트를 통해 컨테이너 기반 애플리케이션의 보안을 적절하게 평가하는데 단계가 효과적인지 확인할 수 있습니다. 각 단계를 진행하는 동안 샘플 애플리케이션이 각 단계를 성공적으로 통과하고 AWS ECR로 푸시될 수 있도록 잘못된 구성이나 취약성을 수정합니다. ### Pipeline Architecture ![](https://i.imgur.com/cA3sxwa.png) 1. **Commit** : 개발자가 Development 분기에 커밋합니다. 1. **풀 리퀘스트** : 개발자가 풀 리퀘스트를 합니다. * 소스 분기: *development* * 대상 지점: *master* 1. **트리거 규칙** : CloudWatch 이벤트 규칙은 다음 이벤트를 기반으로 트리거됩니다. * *pullRequestSource*분기 업데이트됨 * *pullRequest* 생성됨 1. **함수 호출** : AWS Lambda 함수는 CloudWatch 이벤트 규칙의 대상으로 설정되고 CloudWatch 이벤트 규칙이 트리거된 후 호출됩니다. 1. **Posts comment** : Lambda 함수는 보안 테스트가 시작되고 있다는 설명을 Pull Request에 게시합니다. 1. **파이프라인 시작** : Lambda 함수가 CodePipeline을 시작합니다. 1. **풀 리퀘스트 단계** : 단계는 이러한 소스를 가져와서 S3에 아티팩트로 저장합니다. * CodeCommit 리포지토리: container-devsecops-wksp-app(development branch) * CodeCommit 리포지토리: container-devsecops-wksp-config(master branch) 1. **Dockerfile Linting** 단계 : 이 단계는 S3에서 아티팩트를 가져오고 Hadolint(S3에서 가져온 Build spec 파일 및 Configuration 파일)를 사용하여 Dockerfile이 모범 사례를 준수하는지 확인합니다. 1. **Secrets Scanning** 단계 : 이 단계는 CodeCommit 리포지토리(*container-devsecops-wksp-app - development branch*)에 대해 직접 높은 신호 정규식 검사를 실행합니다. 1. **Vulnerability Scanning** 단계 : 이 단계에서는 컨테이너 이미지를 빌드하고 ECR에 푸시하고 이미지에 대해 Anchore 취약성 평가를 트리거합니다. 스캔 결과에 임계값을 충족하거나 초과하는 취약점이 포함된 경우 빌드가 실패합니다. 취약성이 설정된 임계값보다 낮은 경우 CodeBuild 프로젝트는 스캔 결과를 페이로드로 사용하여 Lambda 함수를 호출합니다. 그런 다음 Lambda 함수는 취약성에 대한 위험이 수용되었으므로 향후 분류를 위해 취약성을 AWS Security Hub로 푸시합니다. 1. **이미지 배포** : 이 마지막 단계에서는 대상 커밋 해시를 태그로 사용하여 이미지를 빌드하고 AWS ECR에 배포합니다. 1. **CodeBuild 트리거** : CodeBuild 프로젝트가 실패하면 CloudWatch 이벤트 규칙이 트리거됩니다. 1. **Lambda 함수 트리거** : Lambda 함수는 CloudWatch 이벤트 규칙의 대상으로 설정되고 CloudWatch 이벤트 규칙이 트리거된 후 호출됩니다. 1. **풀 리퀘스트에 피드백 추가** : Lambda 함수는 각 단계와 CodeBuild 프로젝트의 결과를 가져와서 풀 요청에 다시 댓글을 게시합니다. 이를 통해 개발자는 파이프라인을 통해 식별된 모든 문제를 수정할 수 있도록 빠른 피드백을 얻을 수 있습니다. ### 커밋하기 이제 파이프라인을 테스트하여 이미지가 빌드되고 AWS ECR에 푸시되는 pull 요청 결과를 확인할 수 있습니다. 먼저 샘플 애플리케이션 의 개발 분기 에 커밋합니다. 1. Cloud9 IDE 내 에서 왼쪽에 있는 **샘플 애플리케이션**을 확장합니다. 1. **Dockerfile** 을 엽니다. 1. 레이블 라인에 이름을 추가합니다(현재 "Sasquatch"로 설정). 1. 커밋을 푸시합니다. ```bash cd /home/ec2-user/environment/sample-application git add Dockerfile git commit -m "Modified Maintainer in Dockerfile" git push -u origin development ``` ### 풀 리퀘스트 생성 ```bash aws codecommit create-pull-request \ --title "Updated Maintainer" \ --description "Please review these changes." \ --targets repositoryName=container-devsecops-wksp-app,sourceReference=development,destinationReference=master ``` [AWS CodePipeline](https://us-east-2.console.aws.amazon.com/codesuite/codepipeline/pipelines/container-devsecops-wksp-pipeline/view) 으로 이동하여 진행 상황과 결과를 확인하십시오. ### 피드백 루프 보기 단계가 실행될 때마다 CodeBuild 프로젝트의 결과는 개발자를 위한 피드백 루프 역할을 하기 위해 Pull Request에 다시 게시됩니다. 1. [CodeCommit](https://us-east-2.console.aws.amazon.com/codesuite/codecommit/repositories/container-devsecops-wksp-app/pull-requests?region=us-east-2&status=OPEN) 콘솔로 이동 1. container-devsecops-wksp-app 리포지토리를 선택합니다. 1. 좌측 메뉴 트리에서 최신 풀 리퀘스트를 클릭합니다. 1. 활동(Activity) 탭을 클릭하여 피드백을 봅니다. --- ## 모듈 5 : Dockerfile 린트 결함 수정 **소요시간**: 10분 피드백에는 Dockerfile 린팅 단계에서 식별된 여러 결함이 표시되어야 합니다. 첫 번째 결함은 hadolint 구성을 수정하여 수정할 수 있습니다. 1. Cloud9 IDE 탭을 클릭합니다. 1. 왼쪽 파일 트리에서 **configurations** 폴더를 확장하고 **hadolint.yml**을 엽니다. 1. 결함 수정: :::warning :warning: 신뢰할 수 없는 이미지 사용 * **DL3026** : FROM 이미지에서 허용된 레지스트리만 사용하십시오. * **설명** : 외부에서 제공한 이미지를 사용하면 맬웨어 도입, 데이터 유출 또는 취약점이 있는 구성 요소 포함과 같이 외부 소프트웨어가 전통적으로 가지고 있는 것과 동일한 유형의 위험이 발생할 수 있습니다. 외부에서 제공한 이미지의 사용을 방지하려면 신뢰할 수 있는 레지스트리에서만 이미지를 가져와야 합니다. * **수정** : ***trustedRegistries*** 아래에 추가 ```yaml - http://hub.docker.com/ - docker.io - public.ecr.aws ``` * **설명** : 이미지가 Dockerhub에서 가져오기 때문에 빌드가 통과할 수 있도록 목록에 포함할 수 있습니다. Dockerhub를 추가하는 것은 순전히 테스트 목적을 위한 것입니다. 실제로는 자신이 호스팅하는 신뢰할 수 있는 레지스트리 또는 신뢰할 수 있는 타사에서 호스팅하는 레지스트리를 화이트리스트에 추가합니다. * **참조** : [NIST SP 800-190: 애플리케이션 컨테이너 보안 가이드 - 3.1.5](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf) ::: ### 구성 변경 사항을 커밋 ```bash cd /home/ec2-user/environment/configurations git add . git commit -m "Added a trusted registry to hadolint configuration." git push -u origin master ``` 다음 두 가지 결함은 Dockerfile을 수정하여 수정할 수 있습니다. 1. 왼쪽 파일 트리에서 **sample-application** 폴더를 확장하고 **Dockerfile** 을 엽니다. 1. 결함 수정: :::warning :warning: 이미지 구성 결함 1 * **DL3002** : 마지막 사용자는 루트가 아니어야 합니다. * **설명** : 최소 권한의 주체를 준수하려면 컨테이너가 루트로 실행되지 않아야 합니다. 대부분의 컨테이너화된 프로세스는 애플리케이션 서비스이므로 루트 액세스가 필요하지 않습니다. * **수정** : USER를 권한이 없는 사용자로 변경합니다. LABEL maintainer 아래의 Dockerfile에 다음을 추가합니다 . ``` RUN adduser sasquatch -D ``` * 다음으로, `USER root` 를 `USER sasquatch` 로 수정합니다. * **설명** : Dockerfile에 사용자를 생성하면 기본적으로 보안을 유지할 뿐만 아니라 보안을 유지하기 더 쉬워집니다. * **참조** : [NIST SP 800-190: 애플리케이션 컨테이너 보안 가이드 - 3.1.2](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf) ::: :::warning :warning: 이미지 구성 결함 2 * **DL3007** : 이미지가 업데이트될 경우 최신 버전을 사용하면 오류가 발생하기 쉽습니다. * **설명** : Latest는 이미지에 추가하는 태그일 뿐이며 동적이지 않습니다. 덮어쓸 수 있으며 설치된 소프트웨어 버전을 이해하기 어려울 수 있습니다. 최신 태그를 사용하면 애플리케이션의 가용성에 영향을 줄 수 있으므로 보다 명시적인 태그를 사용해야 합니다. * **수정** : 버전을 릴리스 태그에 명시적으로 고정합니다. * `FROM python:latest` 를 `FROM public.ecr.aws/x8q1e6c8/python:3.8-alpine`로 수정합니다. * **참조** : [NIST SP 800-190: 애플리케이션 컨테이너 보안 가이드 - 3.1.2](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf) ::: 애플리케이션 소스 코드 변경 사항을 커밋합니다. ```bash cd /home/ec2-user/environment/sample-application git add Dockerfile git commit -m "Fixed Dockerfile linting issues." git push -u origin development ``` [AWS CodePipeline](https://us-east-2.console.aws.amazon.com/codesuite/codepipeline/pipelines/container-devsecops-wksp-pipeline/view) 으로 이동하여 진행 상황과 결과를 확인하십시오. ### 풀 리퀘스트 피드백 보기 Pull Request 분기를 업데이트하면 파이프라인이 자동으로 다시 트리거됩니다. 피드백을 보고 결함이 수정되었는지 확인할 수 있습니다. 1. [CodeCommit](https://us-east-2.console.aws.amazon.com/codesuite/codecommit/repositories/container-devsecops-wksp-app/pull-requests?region=us-east-2&status=OPEN) 콘솔로 이동 1. 최신 풀 리퀘스트를 클릭합니다. 1. 활동 탭을 클릭하여 피드백을 봅니다. --- ## 모듈 6 : 보안 정보 제거 **소요시간**: 10분 Pull Request에서 받은 피드백을 기반으로 코드에서 비밀값이 식별되었음을 알 수 있습니다. 1. Comment에서 **로그** 를 클릭 하거나 CodeBuild 프로젝트 기록을 확인하여 보안 정보가 있는 파일을 확인합니다. 1. **app/index.py** 파일에서 **access key**를 제거합니다. ### trufflehog 구성 수정 현재 trufflehog 구성은 암호를 식별하기 위해 모든 커밋을 스캔하고 있습니다. 현재 암호를 제거할 것이므로 구성 정보를 수정하여 새 커밋만 스캔하여 빌드 속도를 높일 수 있습니다. 1. 왼쪽 파일 트리에서 **configurations** 폴더를 확장하고 **buildspec_secrets.yml** 을 엽니다. 1. 1 커밋 깊이만 스캔하도록 trufflehog 구성을 업데이트 하십시오. 다음 명령을 변경합니다. `- trufflehog --regex --rules secrets_config.json --entropy=False "$APP_REPO_URL"` 을 `- trufflehog --regex --rules secrets_config.json --entropy=False --max_depth 1 "$APP_REPO_URL"` 로 스캔 깊이를 제한하는 "--max-depth 1"을 추가합니다. 구성 변경 사항을 커밋합니다. ```bash cd /home/ec2-user/environment/configurations git add . git commit -m "Modifed max-depth in trufflehog command." git push -u origin master ``` 애플리케이션 변경 사항을 커밋합니다. ```bash cd /home/ec2-user/environment/sample-application git add . git commit -m "Removed access key." git push -u origin development ``` [AWS CodePipeline](https://us-east-2.console.aws.amazon.com/codesuite/codepipeline/pipelines/container-devsecops-wksp-pipeline/view) 으로 이동하여 진행 상황과 결과를 확인하십시오. 가장 좋은 방법은 모든 이전 커밋에서 비밀정보를 제거하고 발견된 자격 증명을 교체하는 것입니다. 워크샵의 단순성을 위해 비밀정보를 제거하고 새 커밋만 스캔하도록 스캔 도구를 수정했습니다. :::info :exclamation: 다음과 같이 지속적으로 오류가 발생한다면, ``` ... ~~~~~~~~~~~~~~~~~~~~~ Reason: AWS API Key Date: 2021-08-02 05:27:37 Hash: 207436f38228c1b464171e47ea3313f35f5587e0 Filepath: app/index.py Branch: origin/development Commit: Removed access key. AKIAZELJK6BJF5234HAC ~~~~~~~~~~~~~~~~~~~~~ ... ``` git 기록에서 커밋을 제거해야 합니다.(나중에 다른 개발자가 저장소를 다시 복제해야 함) ```bash # After we removed the secret from the index.py file cd /home/ec2-user/environment/sample-application # Need to have a clean working directory git add * git commit -m "Removing secrets from app.py" # Need a perserve a copy of the app file cp app/index.py /home/ec2-user/environment/tmp_index.py # Remove the file from all of git history, other developers will need to reclone repo git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch app/index.py" \ --prune-empty --tag-name-filter cat -- --all # Test the effects of pushing git push --force --verbose --dry-run # ! Warning: this is not reversible ! git push --force # git removes empty dir's so we need to remake it mkdir app # restore the app file from disk cp /home/ec2-user/environment/tmp_index.py app/index.py rm /home/ec2-user/environment/tmp_index.py git add . git commit -m "Removed access key." git push -u origin development ``` * 참조 : [NIST SP 800-190: 애플리케이션 컨테이너 보안 가이드 - 3.1.4](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf) ::: ### 풀 리퀘스트 피드백 보기 Pull Request 분기를 업데이트하면 파이프라인이 자동으로 다시 트리거됩니다. 피드백을 보고 결함이 수정되었는지 확인할 수 있습니다. 1. [CodeCommit](https://us-east-2.console.aws.amazon.com/codesuite/codecommit/repositories/container-devsecops-wksp-app/pull-requests?region=us-east-2&status=OPEN) 콘솔로 이동합니다. 1. 최신 풀 리퀘스트를 클릭합니다. 1. 활동 탭을 클릭하여 피드백을 봅니다. 보안정보 확인 단계에서 파이프라인이 여전히 실패하고 있음을 알 수 있습니다. 스캔 중인 커밋을 보면 액세스 키가 diff의 일부이기 때문에 해당 커밋에 여전히 존재한다는 것을 알 수 있습니다. 한 번 더 커밋하면 빌드가 비밀 스캔 단계를 성공적으로 통과한 것을 볼 수 있습니다. 1. 왼쪽 파일 트리에서 **sample-application** 폴더를 확장하고 **Dockerfile** 을 엽니다. 1. 레이블을 다음으로 변경합니다. ```yaml LABEL maintainer="Sasquatch" version="1.0" ``` 애플리케이션 소스 코드 변경 사항을 커밋합니다. ```bash cd /home/ec2-user/environment/sample-application git add Dockerfile git commit -m "Added version Label." git push -u origin development ``` :::info **:information_source: 텍스트로 포함된 비밀 정보를 제거하십시오** **설명**: 많은 애플리케이션에서 다른 서비스 또는 백엔드 구성 요소와 통신할 수 있도록 비밀이 필요합니다. 애플리케이션이 이미지에 패키징되면 이러한 비밀을 이미지에 직접 포함할 수 있습니다. 이로 인해 이미지에 대한 액세스 권한이 있는 사람이 비밀을 쉽게 얻을 수 있는 보안 위험이 발생합니다. **수정**: 소스 코드에서 비밀을 제거하고 AWS Secrets Manager 또는 AWS Systems Manager Parameter Store와 같은 비밀 관리를 위한 보안 솔루션을 활용하십시오. **해설** 모범사례는 모든 이전 커밋에서 비밀을 제거하고 발견된 자격 증명을 교체하는 것입니다. 워크샵의 단순성을 위해 비밀을 제거하고 새 커밋만 스캔하도록 스캔 도구를 수정했습니다. **선택 사항**: git 기록에서 커밋을 제거하려면(나중에 다른 개발자가 저장소를 다시 복제해야 함): ```bash # After we removed the secret from the index.py file cd /home/ec2-user/environment/sample-application # Need to have a clean working directory git add * git commit -m "Removing secrets from app.py" # Need a perserve a copy of the app file cp app/index.py /home/ec2-user/environment/tmp_index.py # Remove the file from all of git history, other developers will need to reclone repo git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch app/index.py" \ --prune-empty --tag-name-filter cat -- --all # Test the effects of pushing git push --force --verbose --dry-run # ! Warning: this is not reversible ! git push --force # git removes empty dir's so we need to remake it mkdir app # restore the app file from disk cp /home/ec2-user/environment/tmp_index.py app/index.py rm /home/ec2-user/environment/tmp_index.py ``` Reference: [NIST SP 800-190: Application Container Security Guide - 3.1.4](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf) ::: ### 풀 리퀘스트 피드백 보기 Pull Request 분기를 업데이트하면 파이프라인이 자동으로 다시 트리거됩니다. 피드백을 보고 결함이 수정되었는지 확인할 수 있습니다. 1. [CodeCommit](https://us-east-2.console.aws.amazon.com/codesuite/codecommit/repositories/container-devsecops-wksp-app/pull-requests?region=us-east-2&status=OPEN) 콘솔로 이동합니다. 1. 최신 풀 리퀘스트를 클릭합니다. 1. 활동 탭을 클릭하여 피드백을 봅니다. --- ## 모듈 7 : 취약점 확인 **소요시간**: 5분 피드백에서 이미지에서 발견된 취약점에 대한 정보를 볼 수 있습니다. 환경 설정을 진행할 때 취약성 임계값을 **"높음(high)"** 으로 지정했습니다. 이는 이미지에 높음(High) 또는 치명적 취약점이 포함된 경우 빌드가 실패함을 의미합니다. 임계값을 지정하면 다양한 심각도의 취약성에 대한 위험 허용 범위를 설정할 수 있습니다. 이를 통해 개발자는 나중에 분류하고 수정할 수 있는 위험도가 낮은 취약성으로 계속 빠르게 이동할 수 있습니다. 현재 설정에서 임계값 미만의 모든 취약성은 AWS Security Hub로 푸시됩니다. 빌드가 취약점 분석 단계에 실패하므로 이미지에 **"높음(High)"** 등급의 취약점이 포함되지 않도록 문제를 수정해야 합니다. 1. [Security Hub](https://us-east-2.console.aws.amazon.com/securityhub/) 콘솔로 이동합니다. 1. 왼쪽 탐색에서 **Findings**를 클릭합니다. 1. 검색 필드를 클릭하고 **제품명(Product Name)** EQUALS **Default** 필터를 선택하십시오. 결과 결과는 이미지에서 발견된 모든 취약점입니다. **높음(High)** 등급의 취약점을 클릭하고 보고된 취약점에 대한 설명을 확인하십시오. 보고된 취약점에 대한 추가 정보를 보려면 [Source URL](https://nvd.nist.gov/vuln/detail/CVE-2020-25032)의 URL을 따르십시오. ![](https://i.imgur.com/LosH5Ok.png) :::warning :warning: 이미지 취약점 * **설명** : 이미지는 응용 프로그램을 실행하는데 사용되는 모든 구성 요소를 포함하는 정적 아카이브 파일입니다. 이미지 내의 구성 요소에 중요한 보안 업데이트가 누락되었거나 오래되어 악용 및 무단 시스템 액세스로 이어질 수 있습니다. * **수정** : 컨테이너는 변경할 수 없는 것으로 간주되어야 하므로 직접 패치해서는 안 됩니다. 대신 소스 코드와 이미지 구성의 업스트림에서 취약점을 수정한 다음 이미지를 다시 빌드하고 게시해야 합니다. 이렇게 하면 이미지에서 인스턴스화된 모든 새 컨테이너에 취약점이 포함되지 않습니다. * **Dockerfile에서 영향을 받는 패키지 업데이트** : 권장되는 수정에 따라 /sample-application/requirements.txt 에서 flask-cors 버전을 업데이트하십시오 ``` flask-cors <= 3.0.10 ``` * **참조** : [NIST SP 800-190: 애플리케이션 컨테이너 보안 가이드 - 3.1.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf) ::: ### 변경사항 커밋 애플리케이션 소스 코드 변경 사항을 커밋합니다. ```bash cd /home/ec2-user/environment/sample-application git add requirements.txt git commit -m "Update flask-cors version to fix CVE-2020-25032" git push -u origin development ``` ### CodePipeline 보기 Pull Request 분기를 업데이트하면 파이프라인이 자동으로 다시 트리거됩니다. 이번에는 파이프라인으로 이동하여 보안 테스트를 통해 코드 진행 상황을 확인합니다. 1. CodePipeline 콘솔로 이동 1. 코드가 각 단계를 진행하면서 아래로 스크롤합니다. --- ## 모듈 8 : 이미지 보기 **소요시간**: 5분 파이프라인의 마지막 단계는 이미지를 빌드하고 AWS ECR에 게시한 다음 풀 요청을 병합합니다. 피드백에서 이 단계의 결과에 대한 메시지가 게시되고 Pull Request가 병합되었음을 알 수 있습니다. 1. CodeCommit 콘솔로 이동 1. 최신 풀 리퀘스트를 클릭합니다. 마지막 단계에서 이미지를 게시하고 코드를 병합하고 PR을 닫으므로 필터를 "Closed Pull Requests"으로 변경해야 할 수도 있습니다. 1. **활동** 탭을 클릭하여 피드백을 봅니다. 1. **AWS ECR 리포지토리** 링크를 클릭합니다 . 태그 지정 모범 사례에 따라 이미지에 애플리케이션의 Git 커밋 해시 태그가 지정됩니다. :::warning **축하합니다!** :tada: 컨테이너 파이프라인 워크샵에 보안 통합을 완료했습니다. 이제 컨테이너 기반 애플리케이션을 안전하게 빌드하고 게시하기 위한 CI/CD 파이프라인을 완성했습니다. ::: --- ## References * https://container-devsecops.awssecworkshops.com