diff --git a/.dockerignore b/.dockerignore index a49e285..f72f267 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,4 +5,5 @@ sql/queries README.md docker-compose.yml app.sample.env -Dockerfile \ No newline at end of file +Dockerfile +helm diff --git a/.vscode/settings.json b/.vscode/settings.json index b3a18b4..d4a8154 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,13 @@ "mockdb", "sqlc", "stretchr" - ] + ], + "[terraform]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "hashicorp.terraform", + "editor.tabSize": 2, // optionally + }, + "[terraform-vars]": { + "editor.tabSize": 2 // optionally + }, } diff --git a/README.md b/README.md index 0d720e1..eacc881 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@ minikube stop && minikube delete # Deployment - -- Create IAM user -- Create EKS Cluster using [eksctl](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html) \ No newline at end of file +- Create IAM user with required permissions and create access key +- Configure AWS CLI +```bash +aws configure +``` \ No newline at end of file diff --git a/infra/.gitignore b/infra/.gitignore new file mode 100644 index 0000000..6304eb3 --- /dev/null +++ b/infra/.gitignore @@ -0,0 +1,34 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/infra/aws-k8s/.terraform.lock.hcl b/infra/aws-k8s/.terraform.lock.hcl new file mode 100644 index 0000000..cfbebd3 --- /dev/null +++ b/infra/aws-k8s/.terraform.lock.hcl @@ -0,0 +1,182 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.46.0" + constraints = ">= 4.33.0, >= 5.30.0, >= 5.40.0" + hashes = [ + "h1:GK1y1qAGcPHPZxz01Ko6v+815T7kZPXt6POBsLg9c/k=", + "zh:05ae6180a7f23071435f6e5e59c19af0b6c5da42ee600c6c1568c8660214d548", + "zh:0d878d1565d5e57ce6b34ec5f04b28662044a50c999ec5770c374aa1f1020de2", + "zh:25ef1467af2514d8011c44759307445f7057836ff87dfe4503c3e1c9776d5c1a", + "zh:26c006df6200f0063b827aab05bec94f9f3f77848e82ed72e48a51d1170d1961", + "zh:37cdf4292649a10f12858622826925e18ad4eca354c31f61d02c66895eb91274", + "zh:4315b0433c2fc512666c74e989e2d95240934ef370bea1c690d36cb02d30c4ce", + "zh:75df0b3f631b78aeff1832cc77d99b527c2a5e79d40f7aac40bdc4a66124dac2", + "zh:90693d936c9a556d2bf945de4920ff82052002eb73139bd7164fafd02920f0ef", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:c9177ad09804c60fd2ed25950570407b6bdcdf0fcc309e1673b584f06a827fae", + "zh:ca8e8db24a4d62d92afd8d3d383b81a08693acac191a2e0a110fb46deeff56a3", + "zh:d5fa3a36e13957d63bfe9bbd6df0426a2422214403aac9f20b60c36f8d9ebec6", + "zh:e4ede44a112296c9cc77b15e439e41ee15c0e8b3a0dec94ae34df5ebba840e8b", + "zh:f2d4de8d8cde69caffede1544ebea74e69fcc4552e1b79ae053519a05c060706", + "zh:fc19e9266b1841d4a3aeefa8a5b5ad6988baed6540f85a373b6c2d0dc1ca5830", + ] +} + +provider "registry.terraform.io/hashicorp/cloudinit" { + version = "2.3.4" + constraints = ">= 2.0.0" + hashes = [ + "h1:cVIIhnXweOHavu1uV2bdKScTjLbM1WnKM/25wqYBJWo=", + "zh:09f1f1e1d232da96fbf9513b0fb5263bc2fe9bee85697aa15d40bb93835efbeb", + "zh:381e74b90d7a038c3a8dcdcc2ce8c72d6b86da9f208a27f4b98cabe1a1032773", + "zh:398eb321949e28c4c5f7c52e9b1f922a10d0b2b073b7db04cb69318d24ffc5a9", + "zh:4a425679614a8f0fe440845828794e609b35af17db59134c4f9e56d61e979813", + "zh:4d955d8608ece4984c9f1dacda2a59fdb4ea6b0243872f049b388181aab8c80a", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:a48fbee1d58d55a1f4c92c2f38c83a37c8b2f2701ed1a3c926cefb0801fa446a", + "zh:b748fe6631b16a1dafd35a09377c3bffa89552af584cf95f47568b6cd31fc241", + "zh:d4b931f7a54603fa4692a2ec6e498b95464babd2be072bed5c7c2e140a280d99", + "zh:f1c9337fcfe3a7be39d179eb7986c22a979cfb2c587c05f1b3b83064f41785c5", + "zh:f58fc57edd1ee3250a28943cd84de3e4b744cdb52df0356a53403fc240240636", + "zh:f5f50de0923ff530b03e1bca0ac697534d61bb3e5fc7f60e13becb62229097a9", + ] +} + +provider "registry.terraform.io/hashicorp/helm" { + version = "2.13.1" + hashes = [ + "h1:zeDd4IXgLI8JhUt6SRvkjrcIZcPg4fRi0CFcraJgC3c=", + "zh:1bf0ae1ecfd2a5d5a57f695a33b2328ef197138f27ff372fed820c975eac9783", + "zh:4676295e3a929848b98869d3040f54f17fbed3d133342b6a1f7b72d5797239e0", + "zh:4bf3705e061e28d16a525aad9229fdd842cdc96f7c23d040d3148957ba3149d8", + "zh:69db9550eacd61d85cf456d438f08addfefea4fcbc4f4a8119105093ea3d950a", + "zh:6e11560e3ea61b141f03842771bfad143ff1c56bd0d1bc01069496107cad0ab6", + "zh:733ea41e2eb4bd63cfdae6886ed47d224dabb0cd37959c6e2b213b1914a80121", + "zh:74caefb2dc8e6055259d716c11194cc0709261c592d41466abf2dc0b21d88297", + "zh:89682ab50b5cf1f1c41eabfc76f53a56482ac7b4bf77d9cb087d789524fd3e31", + "zh:a5ff95092f2f123027b89f585612a225c9bce7e65977b4ffaf4de3ae3e7870bc", + "zh:c85fce024cb5a387702ceb42a3a06e32519cd1e61bc9dd820a762da21110ab96", + "zh:d828ef2db612798179322bcb3fe829a43dd47e740cabb67e3654c8561ae661ff", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/http" { + version = "3.4.2" + hashes = [ + "h1:eqo0hkFNrixeaT93PC5NiU893s7rUwwOMeqnCjjj3u0=", + "zh:0ba051c9c8659ce0fec94a3d50926745f11759509c4d6de0ad5f5eb289f0edd9", + "zh:23e6760e8406fef645913bf47bfab1ca984c1c5805d2bb0ef8310b16913d29cd", + "zh:3c69fde4548bfe65b968534c4df8d699648c921d6a065b97fec5faece73a442b", + "zh:41c7f9a8c117704b7a8fa96a57ebfb92b72129d9625128eeb0dee7d5a09d1110", + "zh:59d09d2e00727df10565cc82a33250b44201fcd353eb2b1579507a5a0adcce18", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:c95b2f63d4357b3068531b90d9dca62a32551d7693defb7ab14b650b5d139c57", + "zh:cc0a3bbd3026191b35f417d3a8f26bdfad376d15be9e8d99a8803487ca5b0105", + "zh:d1185c6abb3ba25123fb7df1ad7dbe2b9cd8f43962628da551040fbe1934656f", + "zh:dfb26fccab7ecdc150f67415e6cfe19d699dc43e8bf5722f36032b17b46a0fbe", + "zh:eb1fcc00073bc0463f64e49600a73d925b1a0c0ae5b94dd7b67d3ebac248a113", + "zh:ec9b9ad69cf790cb0603a1036d758063bbbc35c0c75f72dd04a1eddaf46ad010", + ] +} + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "2.29.0" + hashes = [ + "h1:oUDANZ62j22EWXtXUDAJe4HFq6BZhrYa4VLk49u7Om0=", + "zh:3edd5dc319b95fe94e61b82d10c1ce7fb53a2f21b067ddb742f2d7d0d19dd113", + "zh:4b9096e6d0cfa0efd4c89270e3d25fea49db570e2cfbe49c5d1de085a15f2578", + "zh:5397573838bcb8844248c8d6ac93cca7f39a0b707ac3ce7a7b306c50c261c195", + "zh:5d635370720d356b7bcb5756ca28de3275ca32ca1ef0201414caecd3a14759ac", + "zh:71a52280408f3fb0ff1866a9ab8059b0d9bde5481869658798e0773461f22eff", + "zh:748663ef0248d2d95f5dea2974332432a395165657856878c5dc6f000b37cc25", + "zh:7fbc1e084bbbb51e31afd3df0c77e833ae59e88cf42b9e2c17b0b1a1e3894723", + "zh:ae89b4be473b446270fa24dc1ef51b0cc4c2a528d9838ec15246d28bac165df3", + "zh:b6433970d680a0cc9898f915224508b5ece86ae4418372fa6bebd2a9d344f226", + "zh:bf871955cf49015e6a0433e814a22a109c1537a775b8b5dc7b37ad05c324904a", + "zh:c16fac91b2197b443a191d98cf37424feed550387ab11bd1427bde819722005e", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/null" { + version = "3.2.2" + constraints = ">= 3.0.0" + hashes = [ + "h1:zT1ZbegaAYHwQa+QwIFugArWikRJI9dqohj8xb0GY88=", + "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7", + "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a", + "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3", + "zh:4c2f1faee67af104f5f9e711c4574ff4d298afaa8a420680b0cb55d7bbc65606", + "zh:544b33b757c0b954dbb87db83a5ad921edd61f02f1dc86c6186a5ea86465b546", + "zh:696cf785090e1e8cf1587499516b0494f47413b43cb99877ad97f5d0de3dc539", + "zh:6e301f34757b5d265ae44467d95306d61bef5e41930be1365f5a8dcf80f59452", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:913a929070c819e59e94bb37a2a253c228f83921136ff4a7aa1a178c7cce5422", + "zh:aa9015926cd152425dbf86d1abdbc74bfe0e1ba3d26b3db35051d7b9ca9f72ae", + "zh:bb04798b016e1e1d49bcc76d62c53b56c88c63d6f2dfe38821afef17c416a0e1", + "zh:c23084e1b23577de22603cff752e59128d83cfecc2e6819edadd8cf7a10af11e", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.6.1" + constraints = ">= 3.1.0" + hashes = [ + "h1:1OlP753r4lOKlBprL0HdZGWerm5DCabD5Mli8k8lWAg=", + "zh:2a0ec154e39911f19c8214acd6241e469157489fc56b6c739f45fbed5896a176", + "zh:57f4e553224a5e849c99131f5e5294be3a7adcabe2d867d8a4fef8d0976e0e52", + "zh:58f09948c608e601bd9d0a9e47dcb78e2b2c13b4bda4d8f097d09152ea9e91c5", + "zh:5c2a297146ed6fb3fe934c800e78380f700f49ff24dbb5fb5463134948e3a65f", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7ce41e26f0603e31cdac849085fc99e5cd5b3b73414c6c6d955c0ceb249b593f", + "zh:8c9e8d30c4ef08ee8bcc4294dbf3c2115cd7d9049c6ba21422bd3471d92faf8a", + "zh:93e91be717a7ffbd6410120eb925ebb8658cc8f563de35a8b53804d33c51c8b0", + "zh:982542e921970d727ce10ed64795bf36c4dec77a5db0741d4665230d12250a0d", + "zh:b9d1873f14d6033e216510ef541c891f44d249464f13cc07d3f782d09c7d18de", + "zh:cfe27faa0bc9556391c8803ade135a5856c34a3fe85b9ae3bdd515013c0c87c1", + "zh:e4aabf3184bbb556b89e4b195eab1514c86a2914dd01c23ad9813ec17e863a8a", + ] +} + +provider "registry.terraform.io/hashicorp/time" { + version = "0.11.1" + constraints = ">= 0.9.0" + hashes = [ + "h1:IkDriv5C9G+kQQ+mP+8QGIahwKgbQcw1/mzh9U6q+ZI=", + "zh:19a393db736ec4fd024d098d55aefaef07056c37a448ece3b55b3f5f4c2c7e4a", + "zh:227fa1e221de2907f37be78d40c06ca6a6f7b243a1ec33ade014dfaf6d92cd9c", + "zh:29970fecbf4a3ca23bacbb05d6b90cdd33dd379f90059fe39e08289951502d9f", + "zh:65024596f22f10e7dcb5e0e4a75277f275b529daa0bc0daf34ca7901c678ab88", + "zh:694d080cb5e3bf5ef08c7409208d061c135a4f5f4cdc93ea8607860995264b2e", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:b29d15d13e1b3412e6a4e1627d378dbd102659132f7488f64017dd6b6d5216d3", + "zh:bb79f4cae9f8c17c73998edc54aa16c2130a03227f7f4e71fc6ac87e230575ec", + "zh:ceccf80e95929d97f62dcf1bb3c7c7553d5757b2d9e7d222518722fc934f7ad5", + "zh:f40e638336527490e294d9c938ae55919069e6987e85a80506784ba90348792a", + "zh:f99ef33b1629a3b2278201142a3011a8489e66d92da832a5b99e442204de18fb", + "zh:fded14754ea46fdecc62a52cd970126420d4cd190e598cb61190b4724a727edb", + ] +} + +provider "registry.terraform.io/hashicorp/tls" { + version = "4.0.5" + constraints = ">= 3.0.0" + hashes = [ + "h1:e4LBdJoZJNOQXPWgOAG0UuPBVhCStu98PieNlqJTmeU=", + "zh:01cfb11cb74654c003f6d4e32bbef8f5969ee2856394a96d127da4949c65153e", + "zh:0472ea1574026aa1e8ca82bb6df2c40cd0478e9336b7a8a64e652119a2fa4f32", + "zh:1a8ddba2b1550c5d02003ea5d6cdda2eef6870ece86c5619f33edd699c9dc14b", + "zh:1e3bb505c000adb12cdf60af5b08f0ed68bc3955b0d4d4a126db5ca4d429eb4a", + "zh:6636401b2463c25e03e68a6b786acf91a311c78444b1dc4f97c539f9f78de22a", + "zh:76858f9d8b460e7b2a338c477671d07286b0d287fd2d2e3214030ae8f61dd56e", + "zh:a13b69fb43cb8746793b3069c4d897bb18f454290b496f19d03c3387d1c9a2dc", + "zh:a90ca81bb9bb509063b736842250ecff0f886a91baae8de65c8430168001dad9", + "zh:c4de401395936e41234f1956ebadbd2ed9f414e6908f27d578614aaa529870d4", + "zh:c657e121af8fde19964482997f0de2d5173217274f6997e16389e7707ed8ece8", + "zh:d68b07a67fbd604c38ec9733069fbf23441436fecf554de6c75c032f82e1ef19", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} diff --git a/infra/aws-k8s/README.md b/infra/aws-k8s/README.md new file mode 100644 index 0000000..2851347 --- /dev/null +++ b/infra/aws-k8s/README.md @@ -0,0 +1,7 @@ +## Infrastructure + +- [VPC](./vpc.tf) +- [EKS](./eks.tf) +- [EKS AWS Load Balancer Controller](./eks-albc.tf) +- [ECR](./ecr.tf) +- [RDS](./rds.tf) \ No newline at end of file diff --git a/infra/aws-k8s/common.tf b/infra/aws-k8s/common.tf new file mode 100644 index 0000000..862d37f --- /dev/null +++ b/infra/aws-k8s/common.tf @@ -0,0 +1,23 @@ +data "aws_availability_zones" "available" {} + +data "aws_region" "current" {} + + +locals { + name = "simplebank" + vpc_cidr = "192.168.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) + + albc_version = "v2.7.2" + albc_sa_name = "aws-load-balancer-controller" + + vpc_id = module.vpc.vpc_id + + cluster_name = module.eks.cluster_name + cluster_endpoint = module.eks.cluster_endpoint + cluster_ca_certificate = module.eks.cluster_certificate_authority_data + cluster_oidc_provder_arn = module.eks.oidc_provider_arn + cluster_oidc_provder_url = module.eks.oidc_provider +} + + diff --git a/infra/aws-k8s/ecr.tf b/infra/aws-k8s/ecr.tf new file mode 100644 index 0000000..8e8c87f --- /dev/null +++ b/infra/aws-k8s/ecr.tf @@ -0,0 +1,10 @@ +resource "aws_ecr_repository" "this" { + name = local.name + + image_tag_mutability = "IMMUTABLE" + force_delete = true + + tags = { + Name = "${local.name}/ECR" + } +} diff --git a/infra/aws-k8s/eks-albc.tf b/infra/aws-k8s/eks-albc.tf new file mode 100644 index 0000000..7a6f507 --- /dev/null +++ b/infra/aws-k8s/eks-albc.tf @@ -0,0 +1,89 @@ +data "http" "lb_controll_iam_policy" { + url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/${local.albc_version}/docs/install/iam_policy.json" + + request_headers = { + Accept = "application/json" + } +} + +resource "aws_iam_policy" "albc" { + name = "${local.name}AWSLoadBalancerControllerIAMPolicy" + policy = data.http.lb_controll_iam_policy.response_body +} + + +data "aws_iam_policy_document" "eks_lb_trust" { + version = "2012-10-17" + statement { + actions = ["sts:AssumeRoleWithWebIdentity"] + effect = "Allow" + + condition { + test = "StringEquals" + variable = "${local.cluster_oidc_provder_url}:sub" + values = ["system:serviceaccount:kube-system:aws-load-balancer-controller"] + } + + condition { + test = "StringEquals" + variable = "${local.cluster_oidc_provder_url}:aud" + values = ["sts.amazonaws.com"] + } + + principals { + identifiers = [local.cluster_oidc_provder_arn] + type = "Federated" + } + } +} + +resource "aws_iam_role" "eks_albc" { + name = "${local.name}AmazonEKSLoadBalancerControllerRole" + assume_role_policy = data.aws_iam_policy_document.eks_lb_trust.json +} + +resource "aws_iam_role_policy_attachment" "lbc_iam_policy" { + policy_arn = aws_iam_policy.albc.arn + role = aws_iam_role.eks_albc.name +} + +resource "kubernetes_service_account" "lbc_sa" { + metadata { + name = local.albc_sa_name + namespace = "kube-system" + annotations = { + "eks.amazonaws.com/role-arn" = aws_iam_role.eks_albc.arn + } + labels = { + "app.kubernetes.io/component" = "controller" + "app.kubernetes.io/name" = local.albc_sa_name + } + } +} + +resource "helm_release" "albc" { + name = "aws-load-balancer-controller" + repository = "https://aws.github.io/eks-charts" + chart = "aws-load-balancer-controller" + + namespace = "kube-system" + + dynamic "set" { + for_each = { + "clusterName" = local.name + "serviceAccount.create" = false + "serviceAccount.name" = local.albc_sa_name + "region" = data.aws_region.current.name + "vpcId" = local.vpc_id + } + content { + name = set.key + value = set.value + } + } + + depends_on = [ + kubernetes_service_account.lbc_sa, + aws_iam_role_policy_attachment.lbc_iam_policy + ] +} diff --git a/infra/aws-k8s/eks.tf b/infra/aws-k8s/eks.tf new file mode 100644 index 0000000..76813a1 --- /dev/null +++ b/infra/aws-k8s/eks.tf @@ -0,0 +1,45 @@ +module "eks" { + source = "terraform-aws-modules/eks/aws" + version = "~> 20.0" + + cluster_name = local.name + cluster_version = "1.29" + + cluster_addons = { + coredns = { + most_recent = true + } + kube-proxy = { + most_recent = true + } + vpc-cni = { + most_recent = true + } + } + + vpc_id = module.vpc.vpc_id + subnet_ids = module.vpc.private_subnets + + + enable_cluster_creator_admin_permissions = true + + cluster_endpoint_private_access = true + cluster_endpoint_public_access = true + + eks_managed_node_groups = { + default_ng = { + # variables reference: https://github.com/terraform-aws-modules/terraform-aws-eks/blob/master/modules/eks-managed-node-group/variables.tf + min_size = 1 + max_size = 4 + desired_size = 2 + + disk_size = 20 + + instance_types = ["t2.micro"] + } + } + + tags = { + Name = "${local.name}/ControlPlane" + } +} diff --git a/infra/aws-k8s/outputs.tf b/infra/aws-k8s/outputs.tf new file mode 100644 index 0000000..28e859b --- /dev/null +++ b/infra/aws-k8s/outputs.tf @@ -0,0 +1,56 @@ +output "vpc_id" { + description = "VPC ID" + value = module.vpc.vpc_id +} + +# EKS Cluster + +output "cluster_name" { + value = module.eks.cluster_name +} + +output "cluster_endpoint" { + value = module.eks.cluster_endpoint +} + +output "cluster_ca_certificate" { + value = module.eks.cluster_certificate_authority_data + sensitive = true +} + +output "oidc_provider_arn" { + description = "IAM OpenID Connector Provider ARN" + value = module.eks.oidc_provider_arn +} + +output "oidc_provider_url" { + description = "IAM OpenID Connector Provider URL" + value = module.eks.oidc_provider +} + +# ECR + +output "ecr_repository" { + value = aws_ecr_repository.this.repository_url + sensitive = true +} + +# RDS + +output "db_username" { + value = module.db.db_instance_username +} + +output "db_endpoint" { + value = module.db.db_instance_endpoint + sensitive = true +} + +output "db_port" { + value = module.db.db_instance_port +} + +output "db_password" { + value = random_password.rds_password.bcrypt_hash + sensitive = true +} diff --git a/infra/aws-k8s/providers.tf b/infra/aws-k8s/providers.tf new file mode 100644 index 0000000..5cc5dfd --- /dev/null +++ b/infra/aws-k8s/providers.tf @@ -0,0 +1,23 @@ +provider "aws" {} + +provider "kubernetes" { + host = local.cluster_endpoint + cluster_ca_certificate = base64decode(local.cluster_ca_certificate) + exec { + api_version = "client.authentication.k8s.io/v1beta1" + args = ["eks", "get-token", "--cluster-name", local.cluster_name] + command = "aws" + } +} + +provider "helm" { + kubernetes { + host = local.cluster_endpoint + cluster_ca_certificate = base64decode(local.cluster_ca_certificate) + exec { + api_version = "client.authentication.k8s.io/v1beta1" + args = ["eks", "get-token", "--cluster-name", local.cluster_name] + command = "aws" + } + } +} diff --git a/infra/aws-k8s/rds.tf b/infra/aws-k8s/rds.tf new file mode 100644 index 0000000..b7a4400 --- /dev/null +++ b/infra/aws-k8s/rds.tf @@ -0,0 +1,59 @@ + +module "security_group" { + source = "terraform-aws-modules/security-group/aws" + version = "~> 5.0" + + name = local.name + description = "Complete PostgreSQL example security group" + vpc_id = module.vpc.vpc_id + + # ingress + ingress_with_cidr_blocks = [ + { + from_port = 5432 + to_port = 5432 + protocol = "tcp" + description = "PostgreSQL access from within VPC" + cidr_blocks = module.vpc.vpc_cidr_block + }, + ] + +} + +resource "random_password" "rds_password" { + length = 32 +} + +module "db" { + source = "terraform-aws-modules/rds/aws" + + identifier = local.name + + db_subnet_group_name = module.vpc.database_subnet_group + vpc_security_group_ids = [module.security_group.security_group_id] + + engine = "postgres" + family = "postgres16" + engine_version = "16.1" + instance_class = "db.t3.micro" + allocated_storage = 10 + + multi_az = false + publicly_accessible = false + create_db_option_group = false + create_db_parameter_group = false + storage_encrypted = false + manage_master_user_password = false + + + db_name = "simple_bank" + username = "aseerkt" + password = random_password.rds_password.bcrypt_hash + port = "5432" + + deletion_protection = false + + tags = { + Name = "${local.name}/RDS" + } +} diff --git a/infra/aws-k8s/variables.tf b/infra/aws-k8s/variables.tf new file mode 100644 index 0000000..e69de29 diff --git a/infra/aws-k8s/versions.tf b/infra/aws-k8s/versions.tf new file mode 100644 index 0000000..6f83215 --- /dev/null +++ b/infra/aws-k8s/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.3.2" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.40" + } + } +} diff --git a/infra/aws-k8s/vpc.tf b/infra/aws-k8s/vpc.tf new file mode 100644 index 0000000..e7c995a --- /dev/null +++ b/infra/aws-k8s/vpc.tf @@ -0,0 +1,31 @@ +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "~> 5.0" + + name = local.name + cidr = "192.168.0.0/16" + + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] + public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 3)] + database_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 6)] + + create_database_subnet_group = true + + enable_nat_gateway = true + enable_dns_support = true + enable_dns_hostnames = true + single_nat_gateway = true + + public_subnet_tags = { + "kubernetes.io/role/elb" = 1 + } + + private_subnet_tags = { + "kubernetes.io/role/internal-elb" = 1 + } + + tags = { + Name = "${local.name}/VPC" + } +} diff --git a/scripts/create-eks.sh b/scripts/create-eks.sh new file mode 100644 index 0000000..445df9b --- /dev/null +++ b/scripts/create-eks.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +CLUSTER_NAME=simplebank + +eksctl create cluster \ + --name "$CLUSTER_NAME" \ + --nodes 3 \ + --nodes-min 1 \ + --nodes-max 4 + +# Installing ack for rds using helm chart +# https://aws-controllers-k8s.github.io/community/docs/tutorials/rds-example/#install-the-ack-service-controller-for-rds + +aws ecr-public get-login-password --region us-east-1 | helm registry login --username AWS --password-stdin public.ecr.aws + +helm install --create-namespace -n ack-system oci://public.ecr.aws/aws-controllers-k8s/rds-chart --version=0.0.27 --generate-name --set=aws.region=us-east-1 + +# Install AWS load balancer controller + +helm repo add eks https://aws.github.io/eks-charts + +wget https://raw.githubusercontent.com/aws/eks-charts/master/stable/aws-load-balancer-controller/crds/crds.yaml + +kubectl apply -f crds.yaml + +helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system \ +--set clusterName=$CLUSTER_NAME \ +--set serviceAccount.create=false \ +--set serviceAccount.name=aws-load-balancer-controller + +# Setup database networking + +RDS_SUBNET_GROUP_NAME="" +RDS_SUBNET_GROUP_DESCRIPTION="" +EKS_VPC_ID=$(aws eks describe-cluster --name="${EKS_CLUSTER_NAME}" \ + --query "cluster.resourcesVpcConfig.vpcId" \ + --output text) +EKS_SUBNET_IDS=$( + aws ec2 describe-subnets \ + --filters "Name=vpc-id,Values=${EKS_VPC_ID}" \ + --query 'Subnets[*].SubnetId' \ + --output text +) + +cat <<-EOF >db-subnet-groups.yaml +apiVersion: rds.services.k8s.aws/v1alpha1 +kind: DBSubnetGroup +metadata: + name: ${RDS_SUBNET_GROUP_NAME} + namespace: ${APP_NAMESPACE} +spec: + name: ${RDS_SUBNET_GROUP_NAME} + description: ${RDS_SUBNET_GROUP_DESCRIPTION} + subnetIDs: +$(printf " - %s\n" ${EKS_SUBNET_IDS}) + tags: [] +EOF + +kubectl apply -f db-subnet-groups.yaml + +# Security Groups for Pods to access RDS database + +RDS_SECURITY_GROUP_NAME="" +RDS_SECURITY_GROUP_DESCRIPTION="" + +EKS_CIDR_RANGE=$( + aws ec2 describe-vpcs \ + --vpc-ids $EKS_VPC_ID \ + --query "Vpcs[].CidrBlock" \ + --output text +) + +RDS_SECURITY_GROUP_ID=$( + aws ec2 create-security-group \ + --group-name "${RDS_SUBNET_GROUP_NAME}" \ + --description "${RDS_SUBNET_GROUP_DESCRIPTION}" \ + --vpc-id "${EKS_VPC_ID}" \ + --output text +) + +aws ec2 authorize-security-group-ingress \ + --group-id "${RDS_SECURITY_GROUP_ID}" \ + --protocol tcp \ + --port 5432 \ + --cidr "${EKS_CIDR_RANGE}" + +# Create secrets that store DB credentials + +RDS_DB_USERNAME="" +RDS_DB_PASSWORD="" + +kubectl create secret generic -n "${APP_NAMESPACE}" jira-postgres-creds \ + --from-literal=username="${RDS_DB_USERNAME}" \ + --from-literal=password="${RDS_DB_PASSWORD}" + +# Create RDS instance + +RDS_DB_INSTANCE_NAME="jira-db" +RDS_DB_INSTANCE_CLASS="db.m6g.large" +RDS_DB_STORAGE_SIZE=100 + +cat <<-EOF >jira-db.yaml +apiVersion: rds.services.k8s.aws/v1alpha1 +kind: DBInstance +metadata: + name: ${RDS_DB_INSTANCE_NAME} + namespace: ${APP_NAMESPACE} +spec: + allocatedStorage: ${RDS_DB_STORAGE_SIZE} + autoMinorVersionUpgrade: true + backupRetentionPeriod: 7 + dbInstanceClass: ${RDS_DB_INSTANCE_CLASS} + dbInstanceIdentifier: ${RDS_DB_INSTANCE_NAME} + dbName: jira + dbSubnetGroupName: ${RDS_SUBNET_GROUP_NAME} + enablePerformanceInsights: true + engine: postgres + engineVersion: "13" + masterUsername: ${RDS_DB_USERNAME} + masterUserPassword: + namespace: ${APP_NAMESPACE} + name: jira-postgres-creds + key: password + multiAZ: true + publiclyAccessible: false + storageEncrypted: true + storageType: gp2 + vpcSecurityGroupIDs: + - ${RDS_SECURITY_GROUP_ID} +EOF + +kubectl apply -f jira-db.yaml diff --git a/scripts/k8s-start.sh b/scripts/k8s-start.sh deleted file mode 100644 index 90dfa6c..0000000 --- a/scripts/k8s-start.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -minikube start - -minikube image build . -t aseerkt/simplebank:latest - -helm install simplebank helm/simplebank \ No newline at end of file