#!/bin/bash
set -oe pipefail

#
# pre-install:
# aws-cli, jq, python3
# python3 packages: boto3
#
# Usage
# ./init-byoc-account-customer.sh mAccountId
#

mAccountId=$1
shift 1

region=us-west-2
accountId=$(aws sts get-caller-identity --query "Account" --output text --no-cli-pager)

function createPolicy() {
  local policyName=$1
  local policyDocument=$2
  local policyList=$(aws iam list-policies \
    --query="Policies[?PolicyName=='$policyName']" \
    --region=$region --no-cli-pager)
  if test $? -ne 0; then
    echo "failed to list policies"
    exit 1
  fi
  local hasCreated=$(echo "$policyList" | jq "length")
  if [[ $hasCreated == "0" ]]; then
    aws iam create-policy --policy-name=$policyName \
      --policy-document="$policyDocument" \
      --region=$region --no-cli-pager > /dev/null
    if test $? -ne 0; then
      echo "failed to create policy $policyName"
      exit 1
    fi
    echo "created iam policy $policyName"
  else
    echo "iam policy $policyName has already created"
    policyArn=$(echo "$policyList" | jq -r '.[0].Arn')
    aws iam create-policy-version --policy-arn=$policyArn \
      --policy-document="$policyDocument" \
      --region=$region --no-cli-pager --set-as-default > /dev/null
    if test $? -ne 0; then
      echo "failed to update iam policy $policyName"
      exit 1
    fi
    echo "update iam policy $policyName"
    # delete old policy version
    oldVersionId=$(echo "$policyList" | jq -r '.[0].DefaultVersionId')
    aws iam delete-policy-version --policy-arn=$policyArn \
      --version-id="$oldVersionId" \
      --region=$region --no-cli-pager > /dev/null
    if test $? -ne 0; then
      echo "warn: failed to delete iam policy version $policyName($oldVersionId)"
    fi
  fi
}

function createRole() {
  local roleName=$1
  local trustPolicy=$2
  local policyArns=$3
  local roleList=$(aws iam list-roles \
    --query="Roles[?RoleName=='$roleName']" \
    --region=$region --no-cli-pager)
  if test $? -ne 0; then
    echo "failed to list roles"
    exit 1
  fi
  local hasCreated=$(echo "$roleList" | jq "length")
  if [[ $hasCreated == "0" ]]; then
    aws iam create-role --role-name=$roleName \
      --assume-role-policy-document="$trustPolicy" \
      --region=$region --no-cli-pager > /dev/null
    if test $? -ne 0; then
      echo "failed to create role $roleName"
      exit 1
    fi
    echo "created iam role $roleName"

    aws iam attach-role-policy --role-name=$roleName \
      --policy-arn="$policyArns" \
      --region=$region
    if test $? -ne 0; then
      echo "failed to set role policy $roleName"
      exit 1
    fi
    echo "added iam role policy $roleName"
  else
    echo "iam role $roleName has already created"
  fi
}

function createRoleWithPolicy() {
  local roleName=$1
  local trustPolicy=$2
  local policy=$3
  local roleList=$(aws iam list-roles \
    --query="Roles[?RoleName=='$roleName']" \
    --region=$region --no-cli-pager)
  if test $? -ne 0; then
    echo "failed to list roles"
    exit 1
  fi
  local hasCreated=$(echo "$roleList" | jq "length")
  if [[ $hasCreated == "0" ]]; then
    aws iam create-role --role-name=$roleName \
      --assume-role-policy-document="$trustPolicy" \
      --region=$region --no-cli-pager > /dev/null
    if test $? -ne 0; then
      echo "failed to create role $roleName"
      exit 1
    fi
    echo "created iam role $roleName"
  else
    echo "iam role $roleName has already created"
  fi
  aws iam put-role-policy --role-name=$roleName \
    --policy-name="$roleName-policy" --policy-document "$policy" \
    --region=$region --no-cli-pager
  if test $? -ne 0; then
    echo "failed to set role policy $roleName"
    exit 1
  fi
  echo "update iam role policy $roleName"
}

# create auto-deploy-cli role
trustPolicy=$(cat <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::$mAccountId:role/auto-deploy-cli"
                ]
            },
            "Action": "sts:AssumeRole"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "accounts.google.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "accounts.google.com:aud": "114667344163696279999"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "accounts.google.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "accounts.google.com:aud": "jenkins-utility-us-west1-cicd@pingcap-dbaas-build.iam.gserviceaccount.com"
                }
            }
        }
    ]
}
EOF
)
policy=$(cat <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:UpdateStack",
                "cloudformation:DescribeStacks",
                "cloudformation:ListStacks",
                "cloudformation:DescribeStackEvents",
                "cloudformation:DescribeStackResource",
                "cloudformation:DescribeStackResources",
                "cloudformation:GetTemplate",
                "cloudformation:ValidateTemplate",
                "cloudformation:GetTemplateSummary",
                "cloudformation:TagResource",
                "cloudformation:UntagResource",
                "cloudformation:CreateChangeSet",
                "cloudformation:DescribeChangeSet",
                "cloudformation:ExecuteChangeSet",
                "cloudformation:DeleteChangeSet",
                "cloudformation:ListChangeSets",
                "iam:AttachRolePolicy",
                "iam:DeleteRolePolicy",
                "iam:DetachRolePolicy",
                "iam:GetRolePolicy",
                "iam:PutRolePolicy",
                "iam:CreatePolicy",
                "iam:DeletePolicy",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:GetRole",
                "iam:GetPolicy",
                "iam:TagRole",
                "iam:TagPolicy",
                "iam:UntagRole",
                "iam:PassRole",
                "iam:ListRolePolicies",
                "iam:ListAttachedRolePolicies",
                "iam:ListPolicyVersions",
                "iam:UpdateAssumeRolePolicy",
                "iam:CreateInstanceProfile",
                "iam:DeleteInstanceProfile",
                "iam:GetInstanceProfile",
                "iam:CreateOpenIDConnectProvider",
                "iam:DeleteOpenIDConnectProvider",
                "iam:GetOpenIDConnectProvider",
                "iam:ListOpenIDConnectProviders",
                "iam:TagOpenIDConnectProvider",
                "iam:UntagOpenIDConnectProvider",
                "iam:ListInstanceProfilesForRole",
                "iam:GetPolicyVersion",
                "iam:CreateServiceLinkedRole"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:AttachInstances",
                "autoscaling:DetachInstances",
                "autoscaling:CreateAutoScalingGroup",
                "autoscaling:DeleteAutoScalingGroup",
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "autoscaling:UpdateAutoScalingGroup",
                "ec2:AllocateAddress",
                "ec2:ReleaseAddress",
                "ec2:DescribeAddresses",
                "ec2:CreateRouteTable",
                "ec2:DeleteRouteTable",
                "ec2:DescribeRouteTables",
                "ec2:AssociateRouteTable",
                "ec2:DisassociateRouteTable",
                "ec2:CreateInternetGateway",
                "ec2:DeleteInternetGateway",
                "ec2:DetachInternetGateway",
                "ec2:AttachInternetGateway",
                "ec2:DescribeInternetGateways",
                "ec2:CreateSecurityGroup",
                "ec2:DeleteSecurityGroup",
                "ec2:DescribeSecurityGroups",
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:CreateLaunchTemplate",
                "ec2:DeleteLaunchTemplate",
                "ec2:CreateLaunchTemplateVersion",
                "ec2:DeleteLaunchTemplateVersions",
                "ec2:DescribeLaunchTemplates",
                "ec2:DescribeLaunchTemplateVersions",
                "ec2:GetLaunchTemplateData",
                "ec2:ModifyLaunchTemplate",
                "ec2:CreateNatGateway",
                "ec2:DeleteNatGateway",
                "ec2:DescribeNatGateways",
                "ec2:CreateRoute",
                "ec2:DeleteRoute",
                "ec2:CreateSubnet",
                "ec2:DeleteSubnet",
                "ec2:DescribeSubnets",
                "ec2:ModifySubnetAttribute",
                "ec2:CreateTags",
                "ec2:DeleteTags",
                "ec2:DescribeTags",
                "ec2:CreateVpc",
                "ec2:DeleteVpc",
                "ec2:DescribeVpcs",
                "ec2:ModifyVpcAttribute",
                "ec2:DescribeInstances",
                "ec2:RunInstances",
                "ec2:TerminateInstances",
                "ec2:DescribeImages",
                "ec2:DescribeInstanceTypeOfferings",
                "ec2:CreateNetworkAclEntry",
                "ec2:DeleteNetworkAclEntry",
                "ec2:DisassociateAddress",
                "ec2:DescribeVpcAttribute",
                "ec2:DescribeSecurityGroupRules",
                "ec2:DescribeAddressesAttribute",
                "ec2:DescribeNetworkInterfaces",
                "ec2:CreateVpcEndpoint",
                "ec2:DeleteVpcEndpoints",
                "ec2:DescribeVpcEndpoints",
                "ec2:ModifyVpcEndpoint",
                "ec2:DescribePrefixLists",
                "vpce:AllowMultiRegion",
                "eks:CreateAddon",
                "eks:DeleteAddon",
                "eks:DescribeAddon",
                "eks:DescribeAddonConfiguration",
                "eks:DescribeAddonVersions",
                "eks:ListAddons",
                "eks:UpdateAddon",
                "eks:CreateCluster",
                "eks:DeleteCluster",
                "eks:DescribeCluster",
                "eks:DescribeClusterVersions",
                "eks:UpdateClusterConfig",
                "eks:UpdateClusterVersion",
                "eks:AssociateIdentityProviderConfig",
                "eks:DisassociateIdentityProviderConfig",
                "eks:CreateNodegroup",
                "eks:DeleteNodegroup",
                "eks:DescribeNodegroup",
                "eks:ListNodegroups",
                "eks:UpdateNodegroupConfig",
                "eks:DescribeUpdate",
                "eks:CreateAccessEntry",
                "eks:DescribeAccessEntry",
                "eks:DeleteAccessEntry",
                "eks:AssociateAccessPolicy",
                "eks:DisassociateAccessPolicy",
                "eks:ListAssociatedAccessPolicies",
                "eks:ListUpdates",
                "eks:TagResource",
                "eks:UntagResource",
                "secretsmanager:ReplicateSecretToRegions",
                "route53:GetHostedZone",
                "route53:ListHostedZonesByName",
                "route53:ListHostedZones",
                "ec2:DescribeAvailabilityZones",
                "route53:ListResourceRecordSets",
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "account:ListRegions",
                "account:GetRegionOptStatus",
                "ec2:DescribeRegions"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:PutMetricAlarm",
                "acm:RequestCertificate",
                "acm:RevokeCertificate",
                "acm:DeleteCertificate",
                "acm:DescribeCertificate",
                "acm:AddTagsToCertificate",
                "wafv2:CreateIPSet",
                "wafv2:DeleteIPSet",
                "wafv2:GetIPSet",
                "wafv2:TagResource",
                "wafv2:UntagResource",
                "wafv2:AssociateWebACL",
                "wafv2:CreateWebACL",
                "wafv2:DeleteWebACL",
                "wafv2:UpdateIPSet",
                "wafv2:UpdateWebACL",
                "wafv2:GetWebACL",
                "wafv2:ListTagsForResource",
                "s3:CreateBucket",
                "s3:ListBucket",
                "s3:CreateBucket",
                "s3:PutBucketPublicAccessBlock",
                "s3:PutBucketPolicy",
                "s3:PutLifecycleConfiguration",
                "elasticloadbalancing:DescribeLoadBalancers",
                "ec2:ModifyVpcEndpointServiceConfiguration",
                "ec2:DescribeVpcEndpointServiceConfigurations",
                "ec2:CreateVpcEndpointServiceConfiguration",
                "ec2:DeleteVpcEndpointServiceConfigurations",
                "ec2:ModifyVpcEndpointServicePermissions",
                "ec2:DescribeVpcEndpointServicePermissions"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Action": [
                "route53-recovery-control-config:ListControlPanels",
                "route53domains:*",
                "route53domains:ListDomains",
                "route53-recovery-readiness:ListReadinessChecks",
                "route53domains:ListOperations"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Sid": "Sli",
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:ListBucket",
                "s3:GetLifecycleConfiguration",
                "s3:PutLifecycleConfiguration",
                "iam:PassRole",
                "glue:CreateDatabase",
                "glue:CreateTable",
                "logs:CreateLogGroup",
                "logs:PutRetentionPolicy",
                "logs:CreateLogStream",
                "firehose:DescribeDeliveryStream",
                "firehose:CreateDeliveryStream"
            ],
            "Resource": "*"
        }
    ]
}
EOF
)
createRoleWithPolicy "auto-deploy-cli" "$trustPolicy" "$policy"

trustPolicy=$(cat <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "accounts.google.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "accounts.google.com:aud": "114667344163696279999"
                }
            }
        }
    ]
}
EOF
)

policy=$(cat <<EOF
{
    "Statement": [
        {
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Effect": "Allow",
            "Resource": [
                "*"
            ],
            "Sid": "GetToken"
        },
        {
            "Action": [
                "ecr:DescribeRepositories"
            ],
            "Effect": "Allow",
            "Resource": [
                "*"
            ],
            "Sid": "CheckRepository"
        },
        {
            "Action": [
                "ecr:CreateRepository",
                "ecr:TagResource"
            ],
            "Condition": {
                "ForAllValues:StringEquals": {
                    "aws:TagKeys": [
                        "ManagedBy"
                    ]
                },
                "StringEquals": {
                    "aws:RequestTag/ManagedBy": "PingCAP"
                }
            },
            "Effect": "Allow",
            "Resource": [
                "*"
            ],
            "Sid": "CreateRepository"
        },
        {
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload",
                "ecr:PutImage"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/ManagedBy": "PingCAP"
                }
            },
            "Effect": "Allow",
            "Resource": [
                "*"
            ],
            "Sid": "PushImage"
        }
    ],
    "Version": "2012-10-17"
}
EOF
)
createRoleWithPolicy "auto-deploy-sync-image" "$trustPolicy" "$policy"

policyDocument=$(cat <<EOF
{
    "Statement": [
        {
            "Action": [
                "iam:*",
                "s3:*",
                "kms:*",
                "route53:*",
                "ecr:*",
                "ec2:*",
                "elasticloadbalancing:*",
                "eks:*",
                "autoscaling:*"
            ],
            "Effect": "Allow",
            "Resource": "*",
            "Sid": "VisualEditor0"
        }
    ],
    "Version": "2012-10-17"
}
EOF
)
createPolicy "autonomous-o11y-rs-control" "$policyDocument"

policyDocument=$(cat <<EOF
{
    "Statement": [
        {
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeVolumesModifications",
                "ecr:ListTagsForResource",
                "ecr:ListImages",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeVolumes",
                "ecr:DescribeRepositories",
                "ec2:UnassignPrivateIpAddresses",
                "ec2:DescribeRouteTables",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetLifecyclePolicy",
                "ecr:DescribeImageScanFindings",
                "ec2:DetachNetworkInterface",
                "ecr:GetLifecyclePolicyPreview",
                "ec2:DescribeTags",
                "ecr:GetDownloadUrlForLayer",
                "ec2:ModifyNetworkInterfaceAttribute",
                "ec2:DeleteNetworkInterface",
                "ecr:GetAuthorizationToken",
                "ec2:AssignPrivateIpAddresses",
                "ec2:DescribeSecurityGroups",
                "ec2:CreateNetworkInterface",
                "ec2:DescribeVpcs",
                "ecr:BatchGetImage",
                "ecr:DescribeImages",
                "ec2:DescribeInstanceTypes",
                "ec2:AttachNetworkInterface",
                "eks:DescribeCluster",
                "ec2:DescribeSubnets",
                "ecr:GetRepositoryPolicy"
            ],
            "Effect": "Allow",
            "Resource": "*",
            "Sid": "VisualEditor0"
        },
        {
            "Action": "ec2:CreateTags",
            "Effect": "Allow",
            "Resource": "arn:aws:ec2:*:*:network-interface/*",
            "Sid": "VisualEditor1"
        }
    ],
    "Version": "2012-10-17"
}
EOF
)
createPolicy "autonomous-o11y-rs-data" "$policyDocument"