diff --git a/iam.tf b/iam.tf new file mode 100644 index 0000000..085fc64 --- /dev/null +++ b/iam.tf @@ -0,0 +1,187 @@ +resource "kubernetes_namespace" "alb_ingress" { + count = (var.enabled && var.k8s_namespace != "kube-system") ? 1 : 0 + + metadata { + name = var.k8s_namespace + } +} + +### iam ### +# Policy +data "aws_iam_policy_document" "alb_ingress" { + count = var.enabled ? 1 : 0 + + statement { + actions = [ + "acm:DescribeCertificate", + "acm:ListCertificates", + "acm:GetCertificate" + ] + resources = [ + "*", + ] + effect = "Allow" + } + + statement { + actions = [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateSecurityGroup", + "ec2:CreateTags", + "ec2:DeleteTags", + "ec2:DeleteSecurityGroup", + "ec2:DescribeAccountAttributes", + "ec2:DescribeAddresses", + "ec2:DescribeInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeInternetGateways", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeTags", + "ec2:DescribeVpcs", + "ec2:ModifyInstanceAttribute", + "ec2:ModifyNetworkInterfaceAttribute", + "ec2:RevokeSecurityGroupIngress" + ] + resources = [ + "*", + ] + effect = "Allow" + } + + statement { + actions = [ + "elasticloadbalancing:AddListenerCertificates", + "elasticloadbalancing:AddTags", + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:CreateLoadBalancer", + "elasticloadbalancing:CreateRule", + "elasticloadbalancing:CreateTargetGroup", + "elasticloadbalancing:DeleteListener", + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:DeleteRule", + "elasticloadbalancing:DeleteTargetGroup", + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:DescribeListenerCertificates", + "elasticloadbalancing:DescribeListeners", + "elasticloadbalancing:DescribeLoadBalancers", + "elasticloadbalancing:DescribeLoadBalancerAttributes", + "elasticloadbalancing:DescribeRules", + "elasticloadbalancing:DescribeSSLPolicies", + "elasticloadbalancing:DescribeTags", + "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeTargetGroupAttributes", + "elasticloadbalancing:DescribeTargetHealth", + "elasticloadbalancing:ModifyListener", + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:ModifyRule", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:RegisterTargets", + "elasticloadbalancing:RemoveListenerCertificates", + "elasticloadbalancing:RemoveTags", + "elasticloadbalancing:SetIpAddressType", + "elasticloadbalancing:SetSecurityGroups", + "elasticloadbalancing:SetSubnets", + "elasticloadbalancing:SetWebACL" + ] + resources = [ + "*", + ] + effect = "Allow" + } + + statement { + actions = [ + "iam:CreateServiceLinkedRole", + "iam:GetServerCertificate", + "iam:ListServerCertificates" + ] + resources = [ + "*", + ] + effect = "Allow" + } + + statement { + actions = [ + "waf-regional:GetWebACLForResource", + "waf-regional:GetWebACL", + "waf-regional:AssociateWebACL", + "waf-regional:DisassociateWebACL" + ] + resources = [ + "*", + ] + effect = "Allow" + } + + statement { + actions = [ + "tag:GetResources", + "tag:TagResources" + ] + resources = [ + "*", + ] + effect = "Allow" + } + + statement { + actions = [ + "waf:GetWebACL" + ] + resources = [ + "*", + ] + effect = "Allow" + } + +} + +resource "aws_iam_policy" "alb_ingress" { + count = var.enabled ? 1 : 0 + name = "${var.cluster_name}-alb-ingress" + path = "/" + description = "Policy for alb-ingress service" + + policy = data.aws_iam_policy_document.alb_ingress[0].json +} + +# Role +data "aws_iam_policy_document" "alb_ingress_assume" { + count = var.enabled ? 1 : 0 + + statement { + actions = ["sts:AssumeRoleWithWebIdentity"] + + principals { + type = "Federated" + identifiers = [var.cluster_identity_oidc_issuer_arn] + } + + condition { + test = "StringEquals" + variable = "${replace(var.cluster_identity_oidc_issuer, "https://", "")}:sub" + + values = [ + "system:serviceaccount:${var.k8s_namespace}:${var.k8s_service_account_name}", + ] + } + + effect = "Allow" + } +} + +resource "aws_iam_role" "alb_ingress" { + count = var.enabled ? 1 : 0 + name = "${var.cluster_name}-alb-ingress" + assume_role_policy = data.aws_iam_policy_document.alb_ingress_assume[0].json +} + +resource "aws_iam_role_policy_attachment" "alb_ingress" { + count = var.enabled ? 1 : 0 + role = aws_iam_role.alb_ingress[0].name + policy_arn = aws_iam_policy.alb_ingress[0].arn +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..5475e7a --- /dev/null +++ b/main.tf @@ -0,0 +1,24 @@ +data "helm_repository" "default" { + name = var.helm_repo_name + url = var.helm_repo_url +} + +resource "helm_release" "alb_ingress" { + count = var.enabled ? 1 : 0 + name = var.helm_release_name + repository = data.helm_repository.default.metadata[0].name + chart = var.helm_chart_name + namespace = var.k8s_namespace + version = var.helm_chart_version + + values = [ + "${templatefile("${path.module}/templates/values.yaml.tpl", + { + "cluster_name" = var.cluster_name, + "alb_ingress_iam_role_arn" = aws_iam_role.alb_ingress[0].arn + "replica_count" = var.replica_count + "ingress_class" = var.ingress_class + }) + }" + ] +} diff --git a/templates/values.yaml.tpl b/templates/values.yaml.tpl new file mode 100644 index 0000000..d8bec3d --- /dev/null +++ b/templates/values.yaml.tpl @@ -0,0 +1,26 @@ +## Resources created by the ALB Ingress controller will be prefixed with this string +## Required +clusterName: ${ cluster_name } + +scope: + ## If provided, the ALB ingress controller will only act on Ingress resources annotated with this class + ## Ref: https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/docs/guide/controller/config.md#limiting-ingress-class + ingressClass: ${ ingress_class } + +rbac: + create: true + serviceAccountAnnotations: + eks.amazonaws.com/role-arn: ${ alb_ingress_iam_role_arn } + +image: + repository: docker.io/amazon/aws-alb-ingress-controller + tag: "v1.1.5" + pullPolicy: IfNotPresent + +replicaCount: ${ replica_count } + +## Auto Discover awsRegion from ec2metadata, set this to true and omit awsRegion when ec2metadata is available. +autoDiscoverAwsRegion: true + +## Auto Discover awsVpcID from ec2metadata, set this to true and omit awsVpcID: " when ec2metadata is available. +autoDiscoverAwsVpcID: true diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..9d07247 --- /dev/null +++ b/variables.tf @@ -0,0 +1,49 @@ +# Required module inputs +variable "cluster_name" {} +variable "cluster_identity_oidc_issuer" {} +variable "cluster_identity_oidc_issuer_arn" {} + +# alb-ingress +variable "enabled" { + type = bool +} + +variable "replica_count" { + default = 3 +} + +variable "ingress_class" { + default = "alb-ingress" +} + +# Helm +variable "helm_chart_name" { + default = "aws-alb-ingress-controller" +} + +variable "helm_chart_version" { + default = "0.1.13" +} + +variable "helm_release_name" { + default = "aws-alb-ingress-controller" +} + +variable "helm_repo_name" { + default = "incubator" +} + +variable "helm_repo_url" { + default = "http://storage.googleapis.com/kubernetes-charts-incubator" +} + +# K8S +variable "k8s_namespace" { + default = "alb-ingress" + description = "The k8s namespace in which the alb-ingress service account has been created" +} + +variable "k8s_service_account_name" { + default = "aws-alb-ingress-controller" + description = "The k8s alb-ingress service account name" +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..c73fc9a --- /dev/null +++ b/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = "~> 0.12.0" + + required_providers { + aws = "~> 2.0" + local = "~> 1.2" + null = "~> 2.0" + helm = "~> 1.0" + } +}