├── .dockerignore ├── .github └── workflows │ └── terraform.yml ├── .gitignore ├── Dockerfile ├── README.md ├── app.py ├── buildspec.yml ├── docs ├── chaos-engineering.png ├── checkov.png ├── gitleak.png ├── hadolint.png ├── kubescape.png ├── prowler.png ├── secops.png ├── slack.png ├── sonarqube.png ├── tfsec.png └── trivy.png ├── iam-role-autenticate-eks.sh ├── ingress-nginx-config └── nginx.yaml ├── k8s-deployment.yaml ├── requirements.txt ├── static ├── background.jpg └── styles.css ├── templates └── index.html └── terraform-infra ├── .terraform.lock.hcl ├── acm.tf ├── backend.tf ├── cloudfront.tf ├── data.tf ├── dev.terraform.tfvars ├── dynamodb.tf ├── ecr.tf ├── eks.tf ├── locals.tf ├── output.tf ├── provider.tf ├── s3.tf ├── variables.tf ├── vpc.tf └── waf.tf /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules/ 2 | **/dist 3 | .git 4 | npm-debug.log 5 | .coverage 6 | .coverage.* 7 | .env 8 | .aws 9 | -------------------------------------------------------------------------------- /.github/workflows/terraform.yml: -------------------------------------------------------------------------------- 1 | name: 'Terraform and Security Scanning' 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | terraform: 7 | description: 'Run Terraform Job (yes/no)' 8 | required: true 9 | default: 'no' 10 | infrastructure-audit: 11 | description: 'Run Infrastructure Audit Job (yes/no)' 12 | required: true 13 | default: 'no' 14 | 15 | permissions: 16 | id-token: write 17 | contents: read 18 | env: 19 | AWS_REGION: ap-south-1 20 | TF_VERSION: 1.2.6 21 | 22 | jobs: 23 | terraform: 24 | name: infrastructure-dev 25 | runs-on: ubuntu-latest 26 | if: ${{ github.event.inputs.terraform == 'yes' }} 27 | defaults: 28 | run: 29 | shell: bash 30 | 31 | steps: 32 | - name: Configure AWS Credentials 33 | uses: aws-actions/configure-aws-credentials@v1 34 | with: 35 | aws-region: ${{ env.AWS_REGION }} 36 | role-to-assume: arn:aws:iam::434605749312:role/aws-deployment-tf 37 | role-session-name: staging-session 38 | - name: Checkout 39 | uses: actions/checkout@v3 40 | 41 | - name: Setup terraform 42 | uses: hashicorp/setup-terraform@v1 43 | with: 44 | terraform_version: ${{ env.TF_VERSION }} 45 | 46 | 47 | - name: Terraform Init, Format, Validate 48 | run: | 49 | terraform init 50 | terraform fmt -check 51 | terraform validate -no-color 52 | working-directory: terraform-infra 53 | 54 | - name: Terraform Plan 55 | run: terraform plan --var-file=dev.terraform.tfvars 56 | working-directory: terraform-infra 57 | - name: Terraform Apply 58 | run: terraform apply --auto-approve --var-file=dev.terraform.tfvars 59 | working-directory: terraform-infra 60 | 61 | 62 | infrastructure-audit: 63 | name: infrastructure-audit 64 | runs-on: ubuntu-latest 65 | if: ${{ github.event.inputs.infrastructure-audit == 'yes' }} 66 | 67 | steps: 68 | - name: Checkout 69 | uses: actions/checkout@v3 70 | 71 | - name: Install tfsec 72 | run: | 73 | wget -q $(wget -qO- https://api.github.com/repos/aquasecurity/tfsec/releases/latest | grep -o -E "https://[^\"]*linux_amd64.tar.gz") -O tfsec.tar.gz 74 | tar -xzf tfsec.tar.gz 75 | sudo install tfsec /usr/local/bin/ 76 | working-directory: terraform-infra 77 | 78 | - name: Run tfsec 79 | run: tfsec . --exclude-downloaded-modules --tfvars-file dev.terraform.tfvars 80 | working-directory: terraform-infra 81 | continue-on-error: true 82 | 83 | - name: Install Checkov 84 | run: pip install checkov 85 | 86 | - name: Run Kubernetes YAMLS files Scan 87 | run: | 88 | checkov -d . --framework kubernetes --download-external-modules true 89 | continue-on-error: true 90 | 91 | - name: Run Checkov IAC Scan 92 | run: | 93 | checkov -d . --framework terraform --download-external-modules true 94 | working-directory: terraform-infra 95 | continue-on-error: true 96 | 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | crash.*.log 11 | 12 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 13 | # password, private keys, and other secrets. These should not be part of version 14 | # control as they are data points which are potentially sensitive and subject 15 | # to change depending on the environment. 16 | *.tfvars 17 | *.tfvars.json 18 | 19 | # Ignore override files as they are usually used to override resources locally and so 20 | # are not checked in 21 | override.tf 22 | override.tf.json 23 | *_override.tf 24 | *_override.tf.json 25 | 26 | # Include override files you do wish to add to version control using negated pattern 27 | # !example_override.tf 28 | 29 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 30 | # example: *tfplan* 31 | 32 | # Ignore CLI configuration files 33 | .terraformrc 34 | terraform.rc -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use an official Python runtime as a parent image 2 | FROM python 3 | 4 | # Set the working directory in the container 5 | WORKDIR /app 6 | 7 | # Copy the current directory contents into the container at /app 8 | COPY static /app/static 9 | COPY templates /app/templates 10 | COPY app.py /app 11 | COPY requirements.txt /app 12 | 13 | 14 | # Install any needed dependencies specified in requirements.txt 15 | RUN pip install --no-cache-dir -r requirements.txt 16 | 17 | # Expose the port Flask is running on 18 | EXPOSE 5000 19 | # Define environment variable 20 | ENV FLASK_APP app.py 21 | 22 | # Run app.py when the container launches 23 | CMD ["flask", "run", "--host=0.0.0.0"] 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AWS DevSecops CICDPipeline 2 |  3 | 4 | **Step 1:** 5 | After successfully creating the infrastructure, add and install the Nginx Ingress Controller and repository using the following Helm commands: 6 | ``` 7 | helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx 8 | helm repo update 9 | helm install ingress-nginx ingress-nginx/ingress-nginx --version 4.10.0 --namespace ingress-nginx --create-namespace --set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-ssl-cert"="acm-cert-arn" -f nginx-config.yaml 10 | ``` 11 | You can also customize the Nginx value: [https://github.com/kubernetes/ingress-nginx] 12 | 13 | **Step 2:** Run a bash script to create and authenticate CodeBuild with AWS EKS and update the EKS cluster's aws-auth ConfigMap with the new role. 14 | 1. chmod +x `iam-role-autenticate-eks.sh` 15 | 2. `./iam-role-autenticate-eks.sh` 16 | 17 | ## Prowler 18 |  19 | 20 | ## GITLEAK 21 |  22 | 23 | ## Sonarqube 24 |  25 | 26 | ## Hadolint 27 |  28 | 29 | ## Trivy 30 |  31 | 32 | ## Slack 33 |  34 | 35 | ## Kubescape 36 |  37 | 38 | 39 | ## TFSEC 40 |  41 | 42 | ## Checkov 43 |  44 | 45 | ## Chaos Engineering 46 |  47 | ## Requirements 48 | 49 | | Name | Version | 50 | |------|---------| 51 | | [terraform](#requirement\_terraform) | >= 0.15.0 | 52 | | [aws](#requirement\_aws) | >= 4.29.0 | 53 | | [random](#requirement\_random) | >= 3.6.0 | 54 | | [template](#requirement\_template) | >= 2.2.0 | 55 | 56 | ## Providers 57 | 58 | | Name | Version | 59 | |------|---------| 60 | | [aws](#provider\_aws) | 5.47.0 | 61 | 62 | ## Modules 63 | 64 | | Name | Source | Version | 65 | |------|--------|---------| 66 | | [acm\_backend](#module\_acm\_backend) | terraform-aws-modules/acm/aws | 4.0.1 | 67 | | [acm\_cf](#module\_acm\_cf) | terraform-aws-modules/acm/aws | 4.0.1 | 68 | | [ui](#module\_ui) | terraform-aws-modules/s3-bucket/aws | 3.3.0 | 69 | | [ui-cf](#module\_ui-cf) | terraform-aws-modules/cloudfront/aws | 3.4.0 | 70 | 71 | ## Resources 72 | 73 | | Name | Type | 74 | |------|------| 75 | | [aws_dynamodb_table.photos_metadata](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table) | resource | 76 | | [aws_ecr_repository.foo](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource | 77 | | [aws_eip.nat](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource | 78 | | [aws_eks_cluster.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster) | resource | 79 | | [aws_eks_node_group.private-nodes-01](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_node_group) | resource | 80 | | [aws_eks_node_group.private-nodes-02](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_node_group) | resource | 81 | | [aws_iam_policy.node_additional_permissions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | 82 | | [aws_iam_role.demo](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 83 | | [aws_iam_role.nodes](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 84 | | [aws_iam_role_policy_attachment.demo-AmazonEKSClusterPolicy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 85 | | [aws_iam_role_policy_attachment.node-additional-permissions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 86 | | [aws_iam_role_policy_attachment.nodes-AmazonEC2ContainerRegistryReadOnly](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 87 | | [aws_iam_role_policy_attachment.nodes-AmazonEKSWorkerNodePolicy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 88 | | [aws_iam_role_policy_attachment.nodes-AmazonEKS_CNI_Policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 89 | | [aws_iam_role_policy_attachment.nodes-EC2RoleForSSM](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 90 | | [aws_iam_role_policy_attachment.nodes-SSMFullAccess](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 91 | | [aws_iam_role_policy_attachment.nodes-SSMManagedInstanceCore](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 92 | | [aws_iam_role_policy_attachment.nodes-SessionManager](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 93 | | [aws_internet_gateway.igw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource | 94 | | [aws_kms_key.kms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | 95 | | [aws_nat_gateway.nat](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource | 96 | | [aws_route_table.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 97 | | [aws_route_table.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 98 | | [aws_route_table_association.private-ap-south-1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 99 | | [aws_route_table_association.private-ap-south-1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 100 | | [aws_route_table_association.public-ap-south-1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 101 | | [aws_route_table_association.public-ap-south-1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 102 | | [aws_subnet.private-ap-south-1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 103 | | [aws_subnet.private-ap-south-1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 104 | | [aws_subnet.public-ap-south-1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 105 | | [aws_subnet.public-ap-south-1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 106 | | [aws_vpc.vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource | 107 | | [aws_wafv2_ip_set.block_ip_set](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_ip_set) | resource | 108 | | [aws_wafv2_web_acl.main_acl](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl) | resource | 109 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 110 | | [aws_iam_policy_document.s3_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 111 | | [aws_route53_zone.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source | 112 | 113 | ## Inputs 114 | 115 | | Name | Description | Type | Default | Required | 116 | |------|-------------|------|---------|:--------:| 117 | | [cluster\_config](#input\_cluster\_config) | Configuration for the cluster, detailing specifics like size, type, and other cluster-related settings. | `any` | n/a | yes | 118 | | [ecr\_names](#input\_ecr\_names) | Names of the Elastic Container Registry repositories required for the deployment. | `any` | n/a | yes | 119 | | [env](#input\_env) | The deployment environment name, e.g., 'prod', 'dev', or 'test'. | `string` | n/a | yes | 120 | | [ui\_conf](#input\_ui\_conf) | UI configuration settings, which may include theming, layout, and feature toggles. | `any` | n/a | yes | 121 | | [vpc\_config](#input\_vpc\_config) | Configuration parameters for the VPC including subnets, CIDR blocks, and other network-related settings. | `any` | n/a | yes | 122 | 123 | ## Outputs 124 | 125 | | Name | Description | 126 | |------|-------------| 127 | | [acm\_arn](#output\_acm\_arn) | n/a | 128 | | [cloudfront\_url](#output\_cloudfront\_url) | The URL of the CloudFront distribution. | 129 | | [dynamodb\_table\_name](#output\_dynamodb\_table\_name) | The name of the DynamoDB table. | 130 | | [ecr\_repository\_details](#output\_ecr\_repository\_details) | Details of the ECR repositories including URLs and ARNs | 131 | | [eks\_values\_private\_nodes\_01](#output\_eks\_values\_private\_nodes\_01) | Values related to the AWS EKS managed node group for private-nodes-01 | 132 | | [eks\_values\_private\_nodes\_02](#output\_eks\_values\_private\_nodes\_02) | Values related to the AWS EKS managed node group for private-nodes-02 | 133 | | [s3\_bucket\_name](#output\_s3\_bucket\_name) | The name of the S3 bucket. | 134 | | [vpc\_details](#output\_vpc\_details) | Details of the main VPC | 135 | 136 | You can find the video at [https://youtu.be/Uxx3Mkgc58k](https://youtu.be/Uxx3Mkgc58k) . 137 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, redirect, render_template, jsonify 2 | import boto3 3 | import uuid 4 | import os 5 | import json 6 | import logging 7 | from werkzeug.utils import secure_filename 8 | 9 | app = Flask(__name__, static_url_path='/static') 10 | logging.basicConfig(level=logging.INFO) 11 | logger = logging.getLogger(__name__) 12 | 13 | s3 = boto3.client('s3') 14 | 15 | # Environment variables 16 | S3_BUCKET = os.getenv('S3_BUCKET', 'default-bucket') 17 | CLOUDFRONT_DOMAIN = os.getenv('CLOUDFRONT_DOMAIN', 'default.cloudfront.net') 18 | 19 | # AWS DynamoDB 20 | dynamodb = boto3.resource('dynamodb', region_name='ap-south-1') 21 | table = dynamodb.Table('PhotosMetadata') 22 | 23 | @app.route('/') 24 | def index(): 25 | return render_template('index.html') 26 | 27 | @app.route('/upload', methods=['POST']) 28 | def upload_file(): 29 | file = request.files['file'] 30 | if file: 31 | original_filename = secure_filename(file.filename) # Safely secure the filename 32 | 33 | # Upload to S3 34 | s3.upload_fileobj(file, S3_BUCKET, original_filename) 35 | 36 | # Generate S3 URL 37 | s3_url = f'https://{S3_BUCKET}.s3.amazonaws.com/{original_filename}' 38 | 39 | # Generate URL from CloudFront 40 | cloudfront_url = f'https://{CLOUDFRONT_DOMAIN}/{original_filename}' 41 | 42 | # Store metadata in DynamoDB 43 | table.put_item( 44 | Item={ 45 | 'photo_id': str(uuid.uuid4()), # Generate a photo ID for internal tracking 46 | 'filename': original_filename, # Store the original filename in DynamoDB 47 | 's3_url': s3_url, 48 | 'cloudfront_url': cloudfront_url 49 | } 50 | ) 51 | logger.info(f"File uploaded successfully. CloudFront URL: {cloudfront_url}") 52 | download_instructions = f"Please download the file using this link: {cloudfront_url}" 53 | 54 | return jsonify({ 55 | 'message': 'File uploaded successfully, processing initiated.', 56 | 'cloudfront_url': cloudfront_url, 57 | 'download_instructions': download_instructions 58 | }) 59 | else: 60 | error_message = 'No file part in the request.' 61 | logger.error(error_message) 62 | return render_template('index.html', error=error_message), 400 63 | 64 | if __name__ == '__main__': 65 | app.run(debug=True, port=5000) 66 | -------------------------------------------------------------------------------- /buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | env: 3 | variables: 4 | AWS_DEFAULT_REGION: "ap-south-1" # Specify the region 5 | REPOSITORY_NAME: "codedevops" # ECR repository name 6 | CLUSTER_NAME: "codedevops" # Cluster name 7 | 8 | phases: 9 | install: 10 | commands: 11 | - export SONAR_SCANNER_VERSION=5.0.1.3006 12 | - export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux 13 | - curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip 14 | - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/ 15 | - export PATH=$SONAR_SCANNER_HOME/bin:$PATH 16 | - export SONAR_SCANNER_OPTS="-server" 17 | - sonar-scanner -Dsonar.organization=ravindrasinghh -Dsonar.projectKey=ravindrasinghh_codedevops -Dsonar.sources=. -Dsonar.host.url=https://sonarcloud.io 18 | - echo "Installing GitLeaks..." 19 | - wget https://github.com/zricethezav/gitleaks/releases/download/v8.0.0/gitleaks_8.0.0_linux_x64.tar.gz 20 | - tar -xzf gitleaks_8.0.0_linux_x64.tar.gz 21 | - mv gitleaks /usr/local/bin/gitleaks 22 | - chmod +x /usr/local/bin/gitleaks 23 | - apt-get install wget apt-transport-https gnupg 24 | - wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | apt-key add - 25 | - echo deb https://aquasecurity.github.io/trivy-repo/deb bionic main | tee -a /etc/apt/sources.list.d/trivy.list 26 | - apt-get update 27 | - apt-get install -y trivy 28 | - echo "Installing Hadolint..." 29 | - wget -O /usr/local/bin/hadolint https://github.com/hadolint/hadolint/releases/download/v2.8.0/hadolint-Linux-x86_64 30 | - chmod +x /usr/local/bin/hadolint 31 | - echo "Hadolint installed successfully!" 32 | - echo Install kubectl 33 | - curl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.9/2020-11-02/bin/linux/amd64/kubectl 34 | - chmod +x ./kubectl 35 | - mv kubectl /usr/local/bin 36 | 37 | 38 | 39 | pre_build: 40 | commands: 41 | - echo Logging in to Amazon ECR....... 42 | - aws ecr get-login-password --region $AWS_DEFAULT_REGION| docker login --username AWS --password-stdin 434605749312.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com 43 | - # Replace with this to your repository URI 44 | - REPOSITORY_URI=434605749312.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$REPOSITORY_NAME 45 | - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) 46 | - echo "Running Hadolint on Dockerfile..." 47 | - hadolint Dockerfile || true 48 | - sed -i 's@CONTAINER_IMAGE@'"$REPOSITORY_URI:$IMAGE_TAG"'@' k8s-deployment.yaml 49 | - # Update Kube config Home Directory 50 | - export KUBECONFIG=$HOME/.kube/config 51 | 52 | build: 53 | commands: 54 | - echo "Scanning repository for secrets with GitLeaks..." 55 | - gitleaks detect --source='.' --report-format=json --report-path=gitleaks-report.json 56 | - echo "Building the Docker image..." 57 | - docker build -t $REPOSITORY_URI:$IMAGE_TAG . 58 | - docker tag $REPOSITORY_URI:$IMAGE_TAG $REPOSITORY_URI:latest 59 | - echo "Scanning for vulnerabilities with Trivy..." 60 | - trivy image 434605749312.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$REPOSITORY_NAME:latest || true 61 | 62 | post_build: 63 | commands: 64 | - echo "Pushing the Docker image..." 65 | - docker push $REPOSITORY_URI:$IMAGE_TAG 66 | - echo "Deploying the application to Kubernetes..." 67 | - CREDENTIALS=$(aws sts assume-role --role-arn arn:aws:iam::434605749312:role/EksCodeBuildKubectlRole --role-session-name codebuild-kubectl --duration-seconds 900) 68 | - export AWS_ACCESS_KEY_ID="$(echo ${CREDENTIALS} | jq -r '.Credentials.AccessKeyId')" 69 | - export AWS_SECRET_ACCESS_KEY="$(echo ${CREDENTIALS} | jq -r '.Credentials.SecretAccessKey')" 70 | - export AWS_SESSION_TOKEN="$(echo ${CREDENTIALS} | jq -r '.Credentials.SessionToken')" 71 | - export AWS_EXPIRATION=$(echo ${CREDENTIALS} | jq -r '.Credentials.Expiration') 72 | - aws eks update-kubeconfig --name $CLUSTER_NAME 73 | - kubectl apply -f k8s-deployment.yaml 74 | - echo "Done Enjoy the Day" 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /docs/chaos-engineering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/chaos-engineering.png -------------------------------------------------------------------------------- /docs/checkov.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/checkov.png -------------------------------------------------------------------------------- /docs/gitleak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/gitleak.png -------------------------------------------------------------------------------- /docs/hadolint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/hadolint.png -------------------------------------------------------------------------------- /docs/kubescape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/kubescape.png -------------------------------------------------------------------------------- /docs/prowler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/prowler.png -------------------------------------------------------------------------------- /docs/secops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/secops.png -------------------------------------------------------------------------------- /docs/slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/slack.png -------------------------------------------------------------------------------- /docs/sonarqube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/sonarqube.png -------------------------------------------------------------------------------- /docs/tfsec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/tfsec.png -------------------------------------------------------------------------------- /docs/trivy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/docs/trivy.png -------------------------------------------------------------------------------- /iam-role-autenticate-eks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Dynamically fetch the AWS Account ID 4 | ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) 5 | ROLE_NAME="EksCodeBuildKubectlRole" 6 | 7 | # Function to check if the IAM role exists 8 | check_role_existence() { 9 | aws iam get-role --role-name $ROLE_NAME > /dev/null 2>&1 10 | echo $? 11 | } 12 | 13 | # Set the trust relationship policy JSON correctly 14 | TRUST_POLICY='{ 15 | "Version": "2012-10-17", 16 | "Statement": [ 17 | { 18 | "Effect": "Allow", 19 | "Principal": { 20 | "AWS": "arn:aws:iam::'"${ACCOUNT_ID}"':root" 21 | }, 22 | "Action": "sts:AssumeRole" 23 | } 24 | ] 25 | }' 26 | 27 | # Create IAM Role if it does not exist 28 | if [ $(check_role_existence) -ne 0 ]; then 29 | echo "Creating IAM role..." 30 | aws iam create-role --role-name $ROLE_NAME --assume-role-policy-document "$TRUST_POLICY" 31 | else 32 | echo "Role already exists, skipping creation..." 33 | fi 34 | 35 | # Define inline policy for describing EKS resources 36 | INLINE_POLICY='{ 37 | "Version": "2012-10-17", 38 | "Statement": [ 39 | { 40 | "Effect": "Allow", 41 | "Action": "eks:Describe*", 42 | "Resource": "*" 43 | } 44 | ] 45 | }' 46 | 47 | # File path for inline policy 48 | POLICY_FILE="/tmp/iam-eks-describe-policy" 49 | echo "$INLINE_POLICY" > $POLICY_FILE 50 | 51 | # Attach the policy to the role 52 | aws iam put-role-policy --role-name $ROLE_NAME --policy-name eks-describe --policy-document "file://$POLICY_FILE" 53 | 54 | # Prepare the role definition for the aws-auth configmap 55 | ROLE_DEF="- rolearn: arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME} 56 | username: build 57 | groups: 58 | - system:masters" 59 | 60 | # Get the current aws-auth ConfigMap and save it 61 | TMP_FILE="/tmp/aws-auth.yml" 62 | kubectl get configmap aws-auth -n kube-system -o yaml > $TMP_FILE 63 | 64 | # Check if the role already exists in the ConfigMap 65 | if ! grep -q "$ROLE_NAME" $TMP_FILE; then 66 | echo "Modifying aws-auth ConfigMap to add new role..." 67 | # Use yq to update the YAML file safely 68 | yq e '.data.mapRoles += "'"$ROLE_DEF"'"' -i $TMP_FILE 69 | # Add last-applied-configuration annotation using current content 70 | CONFIG=$(cat $TMP_FILE | yq e -j -) 71 | yq e '.metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"]=$CONFIG' -i $TMP_FILE --arg CONFIG "$CONFIG" 72 | # Apply the updated ConfigMap 73 | kubectl apply -f $TMP_FILE 74 | else 75 | echo "Role already in aws-auth, no changes made..." 76 | fi 77 | 78 | # Verify the updated ConfigMap 79 | kubectl get configmap aws-auth -o yaml -n kube-system 80 | 81 | -------------------------------------------------------------------------------- /ingress-nginx-config/nginx.yaml: -------------------------------------------------------------------------------- 1 | controller: 2 | replicaCount: 2 3 | minAvailable: 2 4 | resources: 5 | limits: 6 | cpu: 200m 7 | memory: 512Mi 8 | requests: 9 | cpu: 100m 10 | memory: 256Mi 11 | updateStrategy: 12 | type: RollingUpdate 13 | rollingUpdate: 14 | maxUnavailable: 1 15 | metrics: 16 | port: 10254 17 | enabled: true 18 | serviceMonitor: 19 | enabled: false 20 | additionalLabels: 21 | release: "kube-prometheus-stack" 22 | service: 23 | annotations: 24 | prometheus.io/scrape: "true" 25 | prometheus.io/port: "10254" 26 | service: 27 | annotations: 28 | service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp 29 | service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: 'true' 30 | service.beta.kubernetes.io/aws-load-balancer-type: nlb 31 | service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https 32 | service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: 'ELBSecurityPolicy-TLS13-1-2-2021-06' 33 | service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*" 34 | targetPorts: 35 | http: http 36 | https: http 37 | -------------------------------------------------------------------------------- /k8s-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: myapp-config 5 | data: 6 | S3_BUCKET: "codedevops-staging-photoapp-ui" 7 | CLOUDFRONT_DOMAIN: "share.codedevops.cloud" 8 | --- 9 | apiVersion: apps/v1 10 | kind: Deployment 11 | metadata: 12 | name: myapp 13 | spec: 14 | selector: 15 | matchLabels: 16 | app: myapp 17 | replicas: 1 18 | template: 19 | metadata: 20 | labels: 21 | app: myapp 22 | spec: 23 | containers: 24 | - image: CONTAINER_IMAGE 25 | name: myapp 26 | ports: 27 | - containerPort: 5000 28 | imagePullPolicy: Always 29 | env: 30 | - name: S3_BUCKET 31 | valueFrom: 32 | configMapKeyRef: 33 | name: myapp-config 34 | key: S3_BUCKET 35 | - name: CLOUDFRONT_DOMAIN 36 | valueFrom: 37 | configMapKeyRef: 38 | name: myapp-config 39 | key: CLOUDFRONT_DOMAIN 40 | 41 | --- 42 | apiVersion: v1 43 | kind: Service 44 | metadata: 45 | name: myapp 46 | spec: 47 | ports: 48 | - port: 80 #service port #kubeproxy will open port on worker node to which can route traffic to alb 49 | targetPort: 5000 #container port 50 | protocol: TCP 51 | type: ClusterIP 52 | selector: 53 | app: myapp 54 | --- 55 | apiVersion: networking.k8s.io/v1 56 | kind: Ingress 57 | metadata: 58 | name: myapp 59 | annotations: 60 | # Ingress class to use the NGINX Ingress Controller 61 | kubernetes.io/ingress.class: "nginx" 62 | # AWS-specific annotations for SSL and the load balancer 63 | alb.ingress.kubernetes.io/scheme: "internet-facing" 64 | alb.ingress.kubernetes.io/target-type: "ip" 65 | alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]' 66 | alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:ap-south-1:434605749312:certificate/9c87dc98-73ca-40f8-a731-280b943ea7f3" 67 | alb.ingress.kubernetes.io/ssl-redirect: '443' 68 | spec: 69 | 70 | rules: 71 | - host: photoapp.codedevops.cloud 72 | http: 73 | paths: 74 | - path: / 75 | pathType: Exact 76 | backend: 77 | service: 78 | name: myapp 79 | port: 80 | number: 80 81 | - path: /upload 82 | pathType: Prefix 83 | backend: 84 | service: 85 | name: myapp 86 | port: 87 | number: 80 88 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | boto3 3 | -------------------------------------------------------------------------------- /static/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravindrasinghh/Deploying-a-Bulletproof-Photo-Sharing-App-with-DevSecOps-Terraform-AWS-EKS-and-Chaos-Engineering/b54f3e4c60a4329cabfefd26f4b940649c8b9d87/static/background.jpg -------------------------------------------------------------------------------- /static/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url('background.jpg'); 3 | background-size: cover; /* Optional: Adjust the background size */ 4 | } 5 | .custom-file-upload { 6 | display: inline-block; 7 | padding: 10px 20px; 8 | background-color: #4CAF50; 9 | color: white; 10 | font-weight: bold; 11 | cursor: pointer; 12 | border-radius: 5px; 13 | } 14 | 15 | .custom-file-upload input[type="file"] { 16 | display: none; 17 | } 18 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |