public EksStack() { // Read back the default VPC and public subnets, which we will use. var vpc = Output.Create(Ec2.GetVpc.InvokeAsync(new Ec2.GetVpcArgs { Default = true })); var vpcId = vpc.Apply(vpc => vpc.Id); var subnet = vpcId.Apply(id => Ec2.GetSubnetIds.InvokeAsync(new Ec2.GetSubnetIdsArgs { VpcId = id })); var subnetIds = subnet.Apply(s => s.Ids); // Create an IAM role that can be used by our service's task. var eksRole = new Iam.Role("eks-iam-eksRole", new Iam.RoleArgs { AssumeRolePolicy = @"{ ""Version"": ""2008-10-17"", ""Statement"": [{ ""Sid"": """", ""Effect"": ""Allow"", ""Principal"": { ""Service"": ""eks.amazonaws.com"" }, ""Action"": ""sts:AssumeRole"" }] }" }); var eksPolicies = new Dictionary <string, string> { { "service-policy", "arn:aws:iam::aws:policy/AmazonEKSServicePolicy" }, { "cluster-policy", "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" } }; foreach (var(name, policy) in eksPolicies) { var taskExecAttach = new Iam.RolePolicyAttachment($"rpa-{name}", new Iam.RolePolicyAttachmentArgs { Role = eksRole.Name, PolicyArn = policy, }); } // Create an IAM role that can be used by our service's task. var nodeGroupRole = new Iam.Role("nodegroup-iam-role", new Iam.RoleArgs { AssumeRolePolicy = @"{ ""Version"": ""2008-10-17"", ""Statement"": [{ ""Sid"": """", ""Effect"": ""Allow"", ""Principal"": { ""Service"": ""ec2.amazonaws.com"" }, ""Action"": ""sts:AssumeRole"" }] }" }); var nodeGroupPolicies = new Dictionary <string, string> { { "worker", "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" }, { "cni", "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" }, { "registry", "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" } }; foreach (var(name, policy) in nodeGroupPolicies) { var taskExecAttach = new Iam.RolePolicyAttachment($"ngpa-{name}", new Iam.RolePolicyAttachmentArgs { Role = nodeGroupRole.Name, PolicyArn = policy, }); } var clusterSg = new Ec2.SecurityGroup("cluster-sg", new Ec2.SecurityGroupArgs { VpcId = vpcId, Egress = { new Ec2.Inputs.SecurityGroupEgressArgs { Protocol = "-1", FromPort = 0, ToPort = 0, CidrBlocks ={ "0.0.0.0/0" } } }, Ingress = { new Ec2.Inputs.SecurityGroupIngressArgs { Protocol = "tcp", FromPort = 80, ToPort = 80, CidrBlocks ={ "0.0.0.0/0" } } } }); var cluster = new Eks.Cluster("eks-cluster", new Eks.ClusterArgs { RoleArn = eksRole.Arn, VpcConfig = new ClusterVpcConfigArgs { PublicAccessCidrs = { "0.0.0.0/0", }, SecurityGroupIds = { clusterSg.Id, }, SubnetIds = subnetIds, }, }); var nodeGroup = new Eks.NodeGroup("node-group", new Eks.NodeGroupArgs { ClusterName = cluster.Name, NodeGroupName = "demo-eks-nodegroup", NodeRoleArn = nodeGroupRole.Arn, SubnetIds = subnetIds, ScalingConfig = new NodeGroupScalingConfigArgs { DesiredSize = 2, MaxSize = 2, MinSize = 2 }, }); this.Kubeconfig = GenerateKubeconfig(cluster.Endpoint, cluster.CertificateAuthority.Apply(x => x.Data), cluster.Name); var k8sProvider = new K8s.Provider("k8s-provider", new K8s.ProviderArgs { KubeConfig = this.Kubeconfig }, new CustomResourceOptions { DependsOn = { nodeGroup }, }); var appNamespace = new CoreV1.Namespace("app-ns", new NamespaceArgs { Metadata = new ObjectMetaArgs { Name = "joe-duffy", }, }, new CustomResourceOptions { Provider = k8sProvider, }); var appLabels = new InputMap <string> { { "app", "iac-workshop" } }; var deployment = new AppsV1.Deployment("app-dep", new DeploymentArgs { Metadata = new ObjectMetaArgs { Namespace = appNamespace.Metadata.Apply(x => x.Name), }, Spec = new DeploymentSpecArgs { Selector = new LabelSelectorArgs { MatchLabels = appLabels }, Replicas = 1, Template = new PodTemplateSpecArgs { Metadata = new ObjectMetaArgs { Labels = appLabels }, Spec = new PodSpecArgs { Containers = { new ContainerArgs { Name = "iac-workshop", Image = "jocatalin/kubernetes-bootcamp:v2", } } } } }, }, new CustomResourceOptions { Provider = k8sProvider, }); var service = new CoreV1.Service("app-service", new ServiceArgs { Metadata = new ObjectMetaArgs { Namespace = appNamespace.Metadata.Apply(x => x.Name), Labels = deployment.Spec.Apply(spec => spec.Template.Metadata.Labels), }, Spec = new ServiceSpecArgs { Type = "LoadBalancer", Ports = { new ServicePortArgs { Port = 80, TargetPort = 8080 }, }, Selector = deployment.Spec.Apply(spec => spec.Template.Metadata.Labels) }, }, new CustomResourceOptions { Provider = k8sProvider, }); this.Url = service.Status.Apply(status => status.LoadBalancer.Ingress[0].Hostname); }
public MyStack() { // Read back the default VPC and public subnets, which we will use. var vpc = Output.Create(Ec2.GetVpc.InvokeAsync(new Ec2.GetVpcArgs { Default = true })); var vpcId = vpc.Apply(vpc => vpc.Id); var subnet = vpcId.Apply(id => Ec2.GetSubnetIds.InvokeAsync(new Ec2.GetSubnetIdsArgs { VpcId = id })); var subnetIds = subnet.Apply(s => s.Ids); // Create an IAM role that can be used by our service's task. var eksRole = new Iam.Role("eks-iam-eksRole", new Iam.RoleArgs { AssumeRolePolicy = @"{ ""Version"": ""2008-10-17"", ""Statement"": [{ ""Sid"": """", ""Effect"": ""Allow"", ""Principal"": { ""Service"": ""eks.amazonaws.com"" }, ""Action"": ""sts:AssumeRole"" }] }" }); var eksPolicies = new Dictionary <string, string> { { "service-policy", "arn:aws:iam::aws:policy/AmazonEKSServicePolicy" }, { "cluster-policy", "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" } }; foreach (var(name, policy) in eksPolicies) { var taskExecAttach = new Iam.RolePolicyAttachment($"rpa-{name}", new Iam.RolePolicyAttachmentArgs { Role = eksRole.Name, PolicyArn = policy, }); } // Create an IAM role that can be used by our service's task. var nodeGroupRole = new Iam.Role("nodegroup-iam-role", new Iam.RoleArgs { AssumeRolePolicy = @"{ ""Version"": ""2008-10-17"", ""Statement"": [{ ""Sid"": """", ""Effect"": ""Allow"", ""Principal"": { ""Service"": ""ec2.amazonaws.com"" }, ""Action"": ""sts:AssumeRole"" }] }" }); var nodeGroupPolicies = new Dictionary <string, string> { { "worker", "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" }, { "cni", "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" }, { "registry", "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" } }; foreach (var(name, policy) in nodeGroupPolicies) { var taskExecAttach = new Iam.RolePolicyAttachment($"ngpa-{name}", new Iam.RolePolicyAttachmentArgs { Role = nodeGroupRole.Name, PolicyArn = policy, }); } var clusterSg = new Ec2.SecurityGroup("cluster-sg", new Ec2.SecurityGroupArgs { VpcId = vpcId, Egress = { new Ec2.Inputs.SecurityGroupEgressArgs { Protocol = "-1", FromPort = 0, ToPort = 0, CidrBlocks ={ "0.0.0.0/0" } } }, Ingress = { new Ec2.Inputs.SecurityGroupIngressArgs { Protocol = "tcp", FromPort = 80, ToPort = 80, CidrBlocks ={ "0.0.0.0/0" } } } }); var cluster = new Eks.Cluster("eks-cluster", new Eks.ClusterArgs { RoleArn = eksRole.Arn, VpcConfig = new ClusterVpcConfigArgs { PublicAccessCidrs = { "0.0.0.0/0", }, SecurityGroupIds = { clusterSg.Id, }, SubnetIds = subnetIds, }, }); var nodeGroup = new Eks.NodeGroup("node-group", new Eks.NodeGroupArgs { ClusterName = cluster.Name, NodeGroupName = "demo-eks-nodegroup", NodeRoleArn = nodeGroupRole.Arn, SubnetIds = subnetIds, ScalingConfig = new NodeGroupScalingConfigArgs { DesiredSize = 2, MaxSize = 2, MinSize = 2 }, }); this.Kubeconfig = GenerateKubeconfig(cluster.Endpoint, cluster.CertificateAuthority.Apply(x => x.Data), cluster.Name); }
private async Task <IDictionary <string, Output <string> > > Initialize() { // VPC var eksVpc = new Aws.Ec2.Vpc("eksVpc", new Aws.Ec2.VpcArgs { CidrBlock = "10.100.0.0/16", InstanceTenancy = "default", EnableDnsHostnames = true, EnableDnsSupport = true, Tags = { { "Name", "pulumi-eks-vpc" }, }, }); var eksIgw = new Aws.Ec2.InternetGateway("eksIgw", new Aws.Ec2.InternetGatewayArgs { VpcId = eksVpc.Id, Tags = { { "Name", "pulumi-vpc-ig" }, }, }); var eksRouteTable = new Aws.Ec2.RouteTable("eksRouteTable", new Aws.Ec2.RouteTableArgs { VpcId = eksVpc.Id, Routes = { new Aws.Ec2.Inputs.RouteTableRouteArgs { CidrBlock = "0.0.0.0/0", GatewayId = eksIgw.Id, }, }, Tags = { { "Name", "pulumi-vpc-rt" }, }, }); // Subnets, one for each AZ in a region var zones = await Aws.GetAvailabilityZones.InvokeAsync(); var vpcSubnet = new List <Aws.Ec2.Subnet>(); foreach (var range in zones.Names.Select((v, k) => new { Key = k, Value = v })) { vpcSubnet.Add(new Aws.Ec2.Subnet($"vpcSubnet-{range.Key}", new Aws.Ec2.SubnetArgs { AssignIpv6AddressOnCreation = false, VpcId = eksVpc.Id, MapPublicIpOnLaunch = true, CidrBlock = $"10.100.{range.Key}.0/24", AvailabilityZone = range.Value, Tags = { { "Name", $"pulumi-sn-{range.Value}" }, }, })); } var rta = new List <Aws.Ec2.RouteTableAssociation>(); foreach (var range in zones.Names.Select((v, k) => new { Key = k, Value = v })) { rta.Add(new Aws.Ec2.RouteTableAssociation($"rta-{range.Key}", new Aws.Ec2.RouteTableAssociationArgs { RouteTableId = eksRouteTable.Id, SubnetId = vpcSubnet[range.Key].Id, })); } var subnetIds = vpcSubnet.Select(__item => __item.Id).ToList(); var eksSecurityGroup = new Aws.Ec2.SecurityGroup("eksSecurityGroup", new Aws.Ec2.SecurityGroupArgs { VpcId = eksVpc.Id, Description = "Allow all HTTP(s) traffic to EKS Cluster", Tags = { { "Name", "pulumi-cluster-sg" }, }, Ingress = { new Aws.Ec2.Inputs.SecurityGroupIngressArgs { CidrBlocks = { "0.0.0.0/0", }, FromPort = 443, ToPort = 443, Protocol = "tcp", Description = "Allow pods to communicate with the cluster API Server.", }, new Aws.Ec2.Inputs.SecurityGroupIngressArgs { CidrBlocks = { "0.0.0.0/0", }, FromPort = 80, ToPort = 80, Protocol = "tcp", Description = "Allow internet access to pods", }, }, }); // EKS Cluster Role var eksRole = new Aws.Iam.Role("eksRole", new Aws.Iam.RoleArgs { AssumeRolePolicy = JsonSerializer.Serialize(new Dictionary <string, object?> { { "Version", "2012-10-17" }, { "Statement", new[] { new Dictionary <string, object?> { { "Action", "sts:AssumeRole" }, { "Principal", new Dictionary <string, object?> { { "Service", "eks.amazonaws.com" }, } }, { "Effect", "Allow" }, { "Sid", "" }, }, } }, }), }); var servicePolicyAttachment = new Aws.Iam.RolePolicyAttachment("servicePolicyAttachment", new Aws.Iam.RolePolicyAttachmentArgs { Role = eksRole.Id, PolicyArn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy", }); var clusterPolicyAttachment = new Aws.Iam.RolePolicyAttachment("clusterPolicyAttachment", new Aws.Iam.RolePolicyAttachmentArgs { Role = eksRole.Id, PolicyArn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", }); // EC2 NodeGroup Role var ec2Role = new Aws.Iam.Role("ec2Role", new Aws.Iam.RoleArgs { AssumeRolePolicy = JsonSerializer.Serialize(new Dictionary <string, object?> { { "Version", "2012-10-17" }, { "Statement", new[] { new Dictionary <string, object?> { { "Action", "sts:AssumeRole" }, { "Principal", new Dictionary <string, object?> { { "Service", "ec2.amazonaws.com" }, } }, { "Effect", "Allow" }, { "Sid", "" }, }, } }, }), }); var workerNodePolicyAttachment = new Aws.Iam.RolePolicyAttachment("workerNodePolicyAttachment", new Aws.Iam.RolePolicyAttachmentArgs { Role = ec2Role.Id, PolicyArn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", }); var cniPolicyAttachment = new Aws.Iam.RolePolicyAttachment("cniPolicyAttachment", new Aws.Iam.RolePolicyAttachmentArgs { Role = ec2Role.Id, PolicyArn = "arn:aws:iam::aws:policy/AmazonEKSCNIPolicy", }); var registryPolicyAttachment = new Aws.Iam.RolePolicyAttachment("registryPolicyAttachment", new Aws.Iam.RolePolicyAttachmentArgs { Role = ec2Role.Id, PolicyArn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", }); // EKS Cluster var eksCluster = new Aws.Eks.Cluster("eksCluster", new Aws.Eks.ClusterArgs { RoleArn = eksRole.Arn, Tags = { { "Name", "pulumi-eks-cluster" }, }, VpcConfig = new Aws.Eks.Inputs.ClusterVpcConfigArgs { PublicAccessCidrs = { "0.0.0.0/0", }, SecurityGroupIds = { eksSecurityGroup.Id, }, SubnetIds = subnetIds, }, }); var nodeGroup = new Aws.Eks.NodeGroup("nodeGroup", new Aws.Eks.NodeGroupArgs { ClusterName = eksCluster.Name, NodeGroupName = "pulumi-eks-nodegroup", NodeRoleArn = ec2Role.Arn, SubnetIds = subnetIds, Tags = { { "Name", "pulumi-cluster-nodeGroup" }, }, ScalingConfig = new Aws.Eks.Inputs.NodeGroupScalingConfigArgs { DesiredSize = 2, MaxSize = 2, MinSize = 1, }, }); var clusterName = eksCluster.Name; var kubeconfig = Output.Tuple(eksCluster.Endpoint, eksCluster.CertificateAuthority, eksCluster.Name).Apply(values => { var endpoint = values.Item1; var certificateAuthority = values.Item2; var name = values.Item3; return(JsonSerializer.Serialize(new Dictionary <string, object?> { { "apiVersion", "v1" }, { "clusters", new[] { new Dictionary <string, object?> { { "cluster", new Dictionary <string, object?> { { "server", endpoint }, { "certificate-authority-data", certificateAuthority.Data }, } }, { "name", "kubernetes" }, }, } }, { "contexts", new[] { new Dictionary <string, object?> { { "contest", new Dictionary <string, object?> { { "cluster", "kubernetes" }, { "user", "aws" }, } }, }, } }, { "current-context", "aws" }, { "kind", "Config" }, { "users", new[] { new Dictionary <string, object?> { { "name", "aws" }, { "user", new Dictionary <string, object?> { { "exec", new Dictionary <string, object?> { { "apiVersion", "client.authentication.k8s.io/v1alpha1" }, { "command", "aws-iam-authenticator" }, } }, { "args", new[] { "token", "-i", name, } }, } }, }, } }, })); }); return(new Dictionary <string, Output <string> > { { "clusterName", clusterName }, { "kubeconfig", kubeconfig }, }); }