From 5900ec24ec7201ebf17f4e1bfbceeb217f0dfdfe Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Tue, 16 Mar 2021 17:45:34 -0700 Subject: [PATCH 1/8] implemented EKS infra provisioning with CFN Signed-off-by: Sam Alba --- examples/aws-eks/README.md | 7 + .../aws-eks/cfn_template_eks_controlplane.cue | 433 ++++++++++++++++++ .../aws-eks/cfn_template_eks_nodegroup.cue | 311 +++++++++++++ examples/aws-eks/cue.mod/pkg/dagger.io | 1 + examples/aws-eks/infrastructure.cue | 43 ++ examples/aws-eks/main.cue | 21 + 6 files changed, 816 insertions(+) create mode 100644 examples/aws-eks/README.md create mode 100644 examples/aws-eks/cfn_template_eks_controlplane.cue create mode 100644 examples/aws-eks/cfn_template_eks_nodegroup.cue create mode 120000 examples/aws-eks/cue.mod/pkg/dagger.io create mode 100644 examples/aws-eks/infrastructure.cue create mode 100644 examples/aws-eks/main.cue diff --git a/examples/aws-eks/README.md b/examples/aws-eks/README.md new file mode 100644 index 00000000..867d8f4f --- /dev/null +++ b/examples/aws-eks/README.md @@ -0,0 +1,7 @@ +# Kubernetes on AWS (EKS) + +## How to run + +```sh + +``` diff --git a/examples/aws-eks/cfn_template_eks_controlplane.cue b/examples/aws-eks/cfn_template_eks_controlplane.cue new file mode 100644 index 00000000..f1d57659 --- /dev/null +++ b/examples/aws-eks/cfn_template_eks_controlplane.cue @@ -0,0 +1,433 @@ +package main + +#CFNTemplate: eksControlPlane: { + AWSTemplateFormatVersion: "2010-09-09" + Description: "Amazon EKS Sample VPC - Private and Public subnets" + Parameters: { + VpcBlock: { + Type: "String" + Default: "192.168.0.0/16" + Description: "The CIDR range for the VPC. This should be a valid private (RFC 1918) CIDR range." + } + PublicSubnet01Block: { + Type: "String" + Default: "192.168.0.0/18" + Description: "CidrBlock for public subnet 01 within the VPC" + } + PublicSubnet02Block: { + Type: "String" + Default: "192.168.64.0/18" + Description: "CidrBlock for public subnet 02 within the VPC" + } + PrivateSubnet01Block: { + Type: "String" + Default: "192.168.128.0/18" + Description: "CidrBlock for private subnet 01 within the VPC" + } + PrivateSubnet02Block: { + Type: "String" + Default: "192.168.192.0/18" + Description: "CidrBlock for private subnet 02 within the VPC" + } + ClusterName: { + Type: "String" + Description: "The EKS cluster name" + } + // EKSIAMRoleName: { + // Type: "String" + // Description: "The name of the IAM role for the EKS service to assume" + // } + } + Metadata: "AWS::CloudFormation::Interface": ParameterGroups: [ + { + Label: default: "Worker Network Configuration" + Parameters: [ + "VpcBlock", + "PublicSubnet01Block", + "PublicSubnet02Block", + "PrivateSubnet01Block", + "PrivateSubnet02Block", + ] + }, + ] + Resources: { + VPC: { + Type: "AWS::EC2::VPC" + Properties: { + CidrBlock: Ref: "VpcBlock" + EnableDnsSupport: true + EnableDnsHostnames: true + Tags: [ + { + Key: "Name" + Value: "Fn::Sub": "${AWS::StackName}-VPC" + }, + ] + } + } + InternetGateway: Type: "AWS::EC2::InternetGateway" + VPCGatewayAttachment: { + Type: "AWS::EC2::VPCGatewayAttachment" + Properties: { + InternetGatewayId: Ref: "InternetGateway" + VpcId: Ref: "VPC" + } + } + PublicRouteTable: { + Type: "AWS::EC2::RouteTable" + Properties: { + VpcId: Ref: "VPC" + Tags: [ + { + Key: "Name" + Value: "Public Subnets" + }, + { + Key: "Network" + Value: "Public" + }, + ] + } + } + PrivateRouteTable01: { + Type: "AWS::EC2::RouteTable" + Properties: { + VpcId: Ref: "VPC" + Tags: [ + { + Key: "Name" + Value: "Private Subnet AZ1" + }, + { + Key: "Network" + Value: "Private01" + }, + ] + } + } + PrivateRouteTable02: { + Type: "AWS::EC2::RouteTable" + Properties: { + VpcId: Ref: "VPC" + Tags: [ + { + Key: "Name" + Value: "Private Subnet AZ2" + }, + { + Key: "Network" + Value: "Private02" + }, + ] + } + } + PublicRoute: { + DependsOn: "VPCGatewayAttachment" + Type: "AWS::EC2::Route" + Properties: { + RouteTableId: Ref: "PublicRouteTable" + DestinationCidrBlock: "0.0.0.0/0" + GatewayId: Ref: "InternetGateway" + } + } + PrivateRoute01: { + DependsOn: [ + "VPCGatewayAttachment", + "NatGateway01", + ] + Type: "AWS::EC2::Route" + Properties: { + RouteTableId: Ref: "PrivateRouteTable01" + DestinationCidrBlock: "0.0.0.0/0" + NatGatewayId: Ref: "NatGateway01" + } + } + PrivateRoute02: { + DependsOn: [ + "VPCGatewayAttachment", + "NatGateway02", + ] + Type: "AWS::EC2::Route" + Properties: { + RouteTableId: Ref: "PrivateRouteTable02" + DestinationCidrBlock: "0.0.0.0/0" + NatGatewayId: Ref: "NatGateway02" + } + } + NatGateway01: { + DependsOn: [ + "NatGatewayEIP1", + "PublicSubnet01", + "VPCGatewayAttachment", + ] + Type: "AWS::EC2::NatGateway" + Properties: { + AllocationId: "Fn::GetAtt": [ + "NatGatewayEIP1", + "AllocationId", + ] + SubnetId: Ref: "PublicSubnet01" + Tags: [ + { + Key: "Name" + Value: "Fn::Sub": "${AWS::StackName}-NatGatewayAZ1" + }, + ] + } + } + NatGateway02: { + DependsOn: [ + "NatGatewayEIP2", + "PublicSubnet02", + "VPCGatewayAttachment", + ] + Type: "AWS::EC2::NatGateway" + Properties: { + AllocationId: "Fn::GetAtt": [ + "NatGatewayEIP2", + "AllocationId", + ] + SubnetId: Ref: "PublicSubnet02" + Tags: [ + { + Key: "Name" + Value: "Fn::Sub": "${AWS::StackName}-NatGatewayAZ2" + }, + ] + } + } + NatGatewayEIP1: { + DependsOn: [ + "VPCGatewayAttachment", + ] + Type: "AWS::EC2::EIP" + Properties: Domain: "vpc" + } + NatGatewayEIP2: { + DependsOn: [ + "VPCGatewayAttachment", + ] + Type: "AWS::EC2::EIP" + Properties: Domain: "vpc" + } + PublicSubnet01: { + Type: "AWS::EC2::Subnet" + Metadata: Comment: "Subnet 01" + Properties: { + AvailabilityZone: "Fn::Select": [ + "0", + { + "Fn::GetAZs": Ref: "AWS::Region" + }, + ] + CidrBlock: Ref: "PublicSubnet01Block" + VpcId: Ref: "VPC" + Tags: [ + { + Key: "Name" + Value: "Fn::Sub": "${AWS::StackName}-PublicSubnet01" + }, + ] + } + } + PublicSubnet02: { + Type: "AWS::EC2::Subnet" + Metadata: Comment: "Subnet 02" + Properties: { + AvailabilityZone: "Fn::Select": [ + "1", + { + "Fn::GetAZs": Ref: "AWS::Region" + }, + ] + CidrBlock: Ref: "PublicSubnet02Block" + VpcId: Ref: "VPC" + Tags: [ + { + Key: "Name" + Value: "Fn::Sub": "${AWS::StackName}-PublicSubnet02" + }, + ] + } + } + PrivateSubnet01: { + Type: "AWS::EC2::Subnet" + Metadata: Comment: "Subnet 03" + Properties: { + AvailabilityZone: "Fn::Select": [ + "0", + { + "Fn::GetAZs": Ref: "AWS::Region" + }, + ] + CidrBlock: Ref: "PrivateSubnet01Block" + VpcId: Ref: "VPC" + Tags: [ + { + Key: "Name" + Value: "Fn::Sub": "${AWS::StackName}-PrivateSubnet01" + }, + ] + } + } + PrivateSubnet02: { + Type: "AWS::EC2::Subnet" + Metadata: Comment: "Private Subnet 02" + Properties: { + AvailabilityZone: "Fn::Select": [ + "1", + { + "Fn::GetAZs": Ref: "AWS::Region" + }, + ] + CidrBlock: Ref: "PrivateSubnet02Block" + VpcId: Ref: "VPC" + Tags: [ + { + Key: "Name" + Value: "Fn::Sub": "${AWS::StackName}-PrivateSubnet02" + }, + ] + } + } + PublicSubnet01RouteTableAssociation: { + Type: "AWS::EC2::SubnetRouteTableAssociation" + Properties: { + SubnetId: Ref: "PublicSubnet01" + RouteTableId: Ref: "PublicRouteTable" + } + } + PublicSubnet02RouteTableAssociation: { + Type: "AWS::EC2::SubnetRouteTableAssociation" + Properties: { + SubnetId: Ref: "PublicSubnet02" + RouteTableId: Ref: "PublicRouteTable" + } + } + PrivateSubnet01RouteTableAssociation: { + Type: "AWS::EC2::SubnetRouteTableAssociation" + Properties: { + SubnetId: Ref: "PrivateSubnet01" + RouteTableId: Ref: "PrivateRouteTable01" + } + } + PrivateSubnet02RouteTableAssociation: { + Type: "AWS::EC2::SubnetRouteTableAssociation" + Properties: { + SubnetId: Ref: "PrivateSubnet02" + RouteTableId: Ref: "PrivateRouteTable02" + } + } + ControlPlaneSecurityGroup: { + Type: "AWS::EC2::SecurityGroup" + Properties: { + GroupDescription: "Cluster communication with worker nodes" + VpcId: Ref: "VPC" + } + } + EKSIAMRole: { + Type: "AWS::IAM::Role" + Properties: { + AssumeRolePolicyDocument: Statement: [ + { + Effect: "Allow" + Principal: Service: [ + "eks.amazonaws.com", + ] + Action: [ + "sts:AssumeRole", + ] + + }, + ] + // RoleName: Ref: "EKSIAMRoleName" + ManagedPolicyArns: [ + "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", + "arn:aws:iam::aws:policy/AmazonEKSServicePolicy", + ] + } + } + EKSCluster: { + Type: "AWS::EKS::Cluster" + Properties: { + Name: Ref: "ClusterName" + RoleArn: "Fn::GetAtt": ["EKSIAMRole", "Arn"] + ResourcesVpcConfig: { + SecurityGroupIds: [{Ref: "ControlPlaneSecurityGroup"}] + SubnetIds: [ + {Ref: "PublicSubnet01"}, + {Ref: "PublicSubnet02"}, + {Ref: "PrivateSubnet01"}, + {Ref: "PrivateSubnet02"}, + ] + } + } + DependsOn: ["EKSIAMRole", "PublicSubnet01", "PublicSubnet02", "PrivateSubnet01", "PrivateSubnet02", "ControlPlaneSecurityGroup"] + } + } + Outputs: { + SubnetIds: { + Description: "Subnets IDs in the VPC" + Value: "Fn::Join": [ + ",", + [ + { + Ref: "PublicSubnet01" + }, + { + Ref: "PublicSubnet02" + }, + { + Ref: "PrivateSubnet01" + }, + { + Ref: "PrivateSubnet02" + }, + ], + ] + } + PublicSubnets: { + Description: "List of the public subnets" + Value: "Fn::Join": [ + ",", + [ + { + Ref: "PublicSubnet01" + }, + { + Ref: "PublicSubnet02" + }, + ], + ] + } + PrivateSubnets: { + Description: "List of the private subnets" + Value: "Fn::Join": [ + ",", + [ + { + Ref: "PrivateSubnet01" + }, + { + Ref: "PrivateSubnet02" + }, + ], + ] + } + DefaultSecurityGroup: { + Description: "Security group for the cluster control plane communication with worker nodes" + Value: "Fn::Join": [ + ",", + [ + { + Ref: "ControlPlaneSecurityGroup" + }, + ], + ] + } + VPC: { + Description: "The VPC Id" + Value: Ref: "VPC" + } + } +} diff --git a/examples/aws-eks/cfn_template_eks_nodegroup.cue b/examples/aws-eks/cfn_template_eks_nodegroup.cue new file mode 100644 index 00000000..528f71c6 --- /dev/null +++ b/examples/aws-eks/cfn_template_eks_nodegroup.cue @@ -0,0 +1,311 @@ +package main + +#CFNTemplate: eksNodeGroup: { + AWSTemplateFormatVersion: "2010-09-09" + Description: "Amazon EKS - Node Group" + Metadata: "AWS::CloudFormation::Interface": ParameterGroups: [ + { + Label: default: "EKS Cluster" + Parameters: [ + "ClusterName", + "ClusterControlPlaneSecurityGroup", + ] + }, + { + Label: default: "Worker Node Configuration" + Parameters: [ + "NodeGroupName", + "NodeAutoScalingGroupMinSize", + "NodeAutoScalingGroupDesiredCapacity", + "NodeAutoScalingGroupMaxSize", + "NodeInstanceType", + "NodeImageIdSSMParam", + "NodeImageId", + "NodeVolumeSize", + // "KeyName", + "BootstrapArguments", + ] + }, + { + Label: default: "Worker Network Configuration" + Parameters: [ + "VpcId", + "Subnets", + ] + }, + ] + Parameters: { + BootstrapArguments: { + Type: "String" + Default: "" + Description: "Arguments to pass to the bootstrap script. See files/bootstrap.sh in https://github.com/awslabs/amazon-eks-ami" + } + ClusterControlPlaneSecurityGroup: { + Type: "AWS::EC2::SecurityGroup::Id" + Description: "The security group of the cluster control plane." + } + ClusterName: { + Type: "String" + Description: "The cluster name provided when the cluster was created. If it is incorrect, nodes will not be able to join the cluster." + } + // KeyName: { + // Type: "AWS::EC2::KeyPair::KeyName" + // Description: "The EC2 Key Pair to allow SSH access to the instances" + // } + NodeAutoScalingGroupDesiredCapacity: { + Type: "Number" + Default: 3 + Description: "Desired capacity of Node Group ASG." + } + NodeAutoScalingGroupMaxSize: { + Type: "Number" + Default: 4 + Description: "Maximum size of Node Group ASG. Set to at least 1 greater than NodeAutoScalingGroupDesiredCapacity." + } + NodeAutoScalingGroupMinSize: { + Type: "Number" + Default: 1 + Description: "Minimum size of Node Group ASG." + } + NodeGroupName: { + Type: "String" + Description: "Unique identifier for the Node Group." + } + NodeImageId: { + Type: "String" + Default: "" + Description: "(Optional) Specify your own custom image ID. This value overrides any AWS Systems Manager Parameter Store value specified above." + } + NodeImageIdSSMParam: { + Type: "AWS::SSM::Parameter::Value" + Default: "/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id" + Description: "AWS Systems Manager Parameter Store parameter of the AMI ID for the worker node instances." + } + NodeInstanceType: { + Type: "String" + Default: "t3.medium" + ConstraintDescription: "Must be a valid EC2 instance type" + Description: "EC2 instance type for the node instances" + } + NodeVolumeSize: { + Type: "Number" + Default: 20 + Description: "Node volume size" + } + Subnets: { + Type: "List" + Description: "The subnets where workers can be created." + } + VpcId: { + Type: "AWS::EC2::VPC::Id" + Description: "The VPC of the worker instances" + } + } + Conditions: HasNodeImageId: "Fn::Not": [ + { + "Fn::Equals": [ + { + Ref: "NodeImageId" + }, + "", + ] + }, + ] + Resources: { + NodeInstanceRole: { + Type: "AWS::IAM::Role" + Properties: { + AssumeRolePolicyDocument: { + Version: "2012-10-17" + Statement: [ + { + Effect: "Allow" + Principal: Service: [ + "ec2.amazonaws.com", + ] + Action: [ + "sts:AssumeRole", + ] + }, + ] + } + ManagedPolicyArns: [ + "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", + "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", + "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", + ] + Path: "/" + } + } + NodeInstanceProfile: { + Type: "AWS::IAM::InstanceProfile" + Properties: { + Path: "/" + Roles: [ + { + Ref: "NodeInstanceRole" + }, + ] + } + } + NodeSecurityGroup: { + Type: "AWS::EC2::SecurityGroup" + Properties: { + GroupDescription: "Security group for all nodes in the cluster" + Tags: [ + { + Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" + Value: "owned" + }, + ] + VpcId: Ref: "VpcId" + } + } + NodeSecurityGroupIngress: { + Type: "AWS::EC2::SecurityGroupIngress" + DependsOn: "NodeSecurityGroup" + Properties: { + Description: "Allow node to communicate with each other" + FromPort: 0 + GroupId: Ref: "NodeSecurityGroup" + IpProtocol: "-1" + SourceSecurityGroupId: Ref: "NodeSecurityGroup" + ToPort: 65535 + } + } + ClusterControlPlaneSecurityGroupIngress: { + Type: "AWS::EC2::SecurityGroupIngress" + DependsOn: "NodeSecurityGroup" + Properties: { + Description: "Allow pods to communicate with the cluster API Server" + FromPort: 443 + GroupId: Ref: "ClusterControlPlaneSecurityGroup" + IpProtocol: "tcp" + SourceSecurityGroupId: Ref: "NodeSecurityGroup" + ToPort: 443 + } + } + ControlPlaneEgressToNodeSecurityGroup: { + Type: "AWS::EC2::SecurityGroupEgress" + DependsOn: "NodeSecurityGroup" + Properties: { + Description: "Allow the cluster control plane to communicate with worker Kubelet and pods" + DestinationSecurityGroupId: Ref: "NodeSecurityGroup" + FromPort: 1025 + GroupId: Ref: "ClusterControlPlaneSecurityGroup" + IpProtocol: "tcp" + ToPort: 65535 + } + } + ControlPlaneEgressToNodeSecurityGroupOn443: { + Type: "AWS::EC2::SecurityGroupEgress" + DependsOn: "NodeSecurityGroup" + Properties: { + Description: "Allow the cluster control plane to communicate with pods running extension API servers on port 443" + DestinationSecurityGroupId: Ref: "NodeSecurityGroup" + FromPort: 443 + GroupId: Ref: "ClusterControlPlaneSecurityGroup" + IpProtocol: "tcp" + ToPort: 443 + } + } + NodeSecurityGroupFromControlPlaneIngress: { + Type: "AWS::EC2::SecurityGroupIngress" + DependsOn: "NodeSecurityGroup" + Properties: { + Description: "Allow worker Kubelets and pods to receive communication from the cluster control plane" + FromPort: 1025 + GroupId: Ref: "NodeSecurityGroup" + IpProtocol: "tcp" + SourceSecurityGroupId: Ref: "ClusterControlPlaneSecurityGroup" + ToPort: 65535 + } + } + NodeSecurityGroupFromControlPlaneOn443Ingress: { + Type: "AWS::EC2::SecurityGroupIngress" + DependsOn: "NodeSecurityGroup" + Properties: { + Description: "Allow pods running extension API servers on port 443 to receive communication from cluster control plane" + FromPort: 443 + GroupId: Ref: "NodeSecurityGroup" + IpProtocol: "tcp" + SourceSecurityGroupId: Ref: "ClusterControlPlaneSecurityGroup" + ToPort: 443 + } + } + NodeLaunchConfig: { + Type: "AWS::AutoScaling::LaunchConfiguration" + Properties: { + AssociatePublicIpAddress: "true" + BlockDeviceMappings: [ + { + DeviceName: "/dev/xvda" + Ebs: { + DeleteOnTermination: true + VolumeSize: Ref: "NodeVolumeSize" + VolumeType: "gp2" + } + }, + ] + IamInstanceProfile: Ref: "NodeInstanceProfile" + ImageId: "Fn::If": [ + "HasNodeImageId", + { + Ref: "NodeImageId" + }, + { + Ref: "NodeImageIdSSMParam" + }, + ] + InstanceType: Ref: "NodeInstanceType" + // KeyName: Ref: "KeyName" + SecurityGroups: [ + { + Ref: "NodeSecurityGroup" + }, + ] + UserData: "Fn::Base64": "Fn::Sub": "#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ${ClusterName} ${BootstrapArguments}\n/opt/aws/bin/cfn-signal --exit-code $? \\\n --stack ${AWS::StackName} \\\n --resource NodeGroup \\\n --region ${AWS::Region}\n" + } + } + NodeGroup: { + Type: "AWS::AutoScaling::AutoScalingGroup" + Properties: { + DesiredCapacity: Ref: "NodeAutoScalingGroupDesiredCapacity" + LaunchConfigurationName: Ref: "NodeLaunchConfig" + MaxSize: Ref: "NodeAutoScalingGroupMaxSize" + MinSize: Ref: "NodeAutoScalingGroupMinSize" + Tags: [ + { + Key: "Name" + PropagateAtLaunch: "true" + Value: "Fn::Sub": "${ClusterName}-${NodeGroupName}-Node" + }, + { + Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" + PropagateAtLaunch: "true" + Value: "owned" + }, + ] + VPCZoneIdentifier: Ref: "Subnets" + } + UpdatePolicy: AutoScalingRollingUpdate: { + MaxBatchSize: "1" + MinInstancesInService: Ref: "NodeAutoScalingGroupDesiredCapacity" + PauseTime: "PT5M" + } + } + } + Outputs: { + NodeInstanceRole: { + Description: "The node instance role" + Value: "Fn::GetAtt": [ + "NodeInstanceRole", + "Arn", + ] + } + NodeSecurityGroup: { + Description: "The security group for the node group" + Value: Ref: "NodeSecurityGroup" + } + } +} diff --git a/examples/aws-eks/cue.mod/pkg/dagger.io b/examples/aws-eks/cue.mod/pkg/dagger.io new file mode 120000 index 00000000..1aafa4de --- /dev/null +++ b/examples/aws-eks/cue.mod/pkg/dagger.io @@ -0,0 +1 @@ +../../../../stdlib \ No newline at end of file diff --git a/examples/aws-eks/infrastructure.cue b/examples/aws-eks/infrastructure.cue new file mode 100644 index 00000000..1083e9a2 --- /dev/null +++ b/examples/aws-eks/infrastructure.cue @@ -0,0 +1,43 @@ +package main + +import ( + "encoding/json" + + "dagger.io/aws" + "dagger.io/aws/cloudformation" +) + +#Infrastructure: { + awsConfig: aws.#Config + namePrefix: *"dagger-example-" | string + // Cluster size is 1 for example (to limit resources) + workerNodeCapacity: *1 | >1 + workerNodeInstanceType: *"t3.small" | string + + let clusterName = "\(namePrefix)eks-cluster" + + eksControlPlane: cloudformation.#Stack & { + config: awsConfig + source: json.Marshal(#CFNTemplate.eksControlPlane) + stackName: "\(namePrefix)eks-controlplane" + neverUpdate: true + parameters: ClusterName: clusterName + } + + eksNodeGroup: cloudformation.#Stack & { + config: awsConfig + source: json.Marshal(#CFNTemplate.eksNodeGroup) + stackName: "\(namePrefix)eks-nodegroup" + neverUpdate: true + parameters: { + ClusterName: clusterName + ClusterControlPlaneSecurityGroup: eksControlPlane.outputs.DefaultSecurityGroup + NodeAutoScalingGroupDesiredCapacity: 1 + NodeAutoScalingGroupMaxSize: NodeAutoScalingGroupDesiredCapacity + 1 + NodeGroupName: "\(namePrefix)eks-nodegroup" + NodeInstanceType: workerNodeInstanceType + VpcId: eksControlPlane.outputs.VPC + Subnets: eksControlPlane.outputs.SubnetIds + } + } +} diff --git a/examples/aws-eks/main.cue b/examples/aws-eks/main.cue new file mode 100644 index 00000000..d126a729 --- /dev/null +++ b/examples/aws-eks/main.cue @@ -0,0 +1,21 @@ +package main + +import ( + "dagger.io/aws" +) + +// Fill using: +// --input-string awsConfig.accessKey=XXX +// --input-string awsConfig.secretKey=XXX +awsConfig: aws.#Config & { + region: *"us-east-2" | string +} + +// Auto-provision an EKS cluster: +// - VPC, Nat Gateways, Subnets, Security Group +// - EKS Cluster +// - Instance Node Group: auto-scaling-group, ec2 instances, etc... +// base config can be changed (number of EC2 instances, types, etc...) +infra: #Infrastructure & { + "awsConfig": awsConfig +} From d282180ae61b54b061f147732116a6cc3f7c2b27 Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Wed, 17 Mar 2021 15:30:14 -0700 Subject: [PATCH 2/8] stdlib: fixed deprecation error in cloudformation.cue Signed-off-by: Sam Alba --- stdlib/aws/cloudformation/cloudformation.cue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/aws/cloudformation/cloudformation.cue b/stdlib/aws/cloudformation/cloudformation.cue index b27a38c7..39e1f6bb 100644 --- a/stdlib/aws/cloudformation/cloudformation.cue +++ b/stdlib/aws/cloudformation/cloudformation.cue @@ -45,9 +45,9 @@ import ( } } - outputs: { - [string]: string + outputs: [string]: string + outputs: { #compute: [ llb.#Load & { from: alpine.#Image & { From f7457e2cba82addfd1d4cd6439a7417e8df471b1 Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Thu, 18 Mar 2021 10:42:45 -0700 Subject: [PATCH 3/8] Simplified infra args to be more intuitive + moved EKS worker node group to managed nodes instead of plain ec2 instances Signed-off-by: Sam Alba --- examples/aws-eks/README.md | 4 +- .../aws-eks/cfn_template_eks_controlplane.cue | 24 +- .../aws-eks/cfn_template_eks_nodegroup.cue | 262 ++---------------- examples/aws-eks/cue.mod/module.cue | 1 + examples/aws-eks/infrastructure.cue | 14 +- examples/aws-eks/main.cue | 4 + 6 files changed, 53 insertions(+), 256 deletions(-) create mode 100644 examples/aws-eks/cue.mod/module.cue diff --git a/examples/aws-eks/README.md b/examples/aws-eks/README.md index 867d8f4f..ae70f397 100644 --- a/examples/aws-eks/README.md +++ b/examples/aws-eks/README.md @@ -3,5 +3,7 @@ ## How to run ```sh - +dagger compute . \ + --input-string awsConfig.accessKey="MY_AWS_ACCESS_KEY" \ + --input-string awsConfig.secretKey="MY_AWS_SECRET_KEY" ``` diff --git a/examples/aws-eks/cfn_template_eks_controlplane.cue b/examples/aws-eks/cfn_template_eks_controlplane.cue index f1d57659..522cc67e 100644 --- a/examples/aws-eks/cfn_template_eks_controlplane.cue +++ b/examples/aws-eks/cfn_template_eks_controlplane.cue @@ -33,10 +33,6 @@ package main Type: "String" Description: "The EKS cluster name" } - // EKSIAMRoleName: { - // Type: "String" - // Description: "The name of the IAM role for the EKS service to assume" - // } } Metadata: "AWS::CloudFormation::Interface": ParameterGroups: [ { @@ -214,6 +210,7 @@ package main Type: "AWS::EC2::Subnet" Metadata: Comment: "Subnet 01" Properties: { + MapPublicIpOnLaunch: true AvailabilityZone: "Fn::Select": [ "0", { @@ -227,6 +224,10 @@ package main Key: "Name" Value: "Fn::Sub": "${AWS::StackName}-PublicSubnet01" }, + { + Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" + Value: "shared" + }, ] } } @@ -234,6 +235,7 @@ package main Type: "AWS::EC2::Subnet" Metadata: Comment: "Subnet 02" Properties: { + MapPublicIpOnLaunch: true AvailabilityZone: "Fn::Select": [ "1", { @@ -247,6 +249,10 @@ package main Key: "Name" Value: "Fn::Sub": "${AWS::StackName}-PublicSubnet02" }, + { + Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" + Value: "shared" + }, ] } } @@ -267,6 +273,10 @@ package main Key: "Name" Value: "Fn::Sub": "${AWS::StackName}-PrivateSubnet01" }, + { + Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" + Value: "shared" + }, ] } } @@ -287,6 +297,10 @@ package main Key: "Name" Value: "Fn::Sub": "${AWS::StackName}-PrivateSubnet02" }, + { + Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" + Value: "shared" + }, ] } } @@ -340,7 +354,6 @@ package main }, ] - // RoleName: Ref: "EKSIAMRoleName" ManagedPolicyArns: [ "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", "arn:aws:iam::aws:policy/AmazonEKSServicePolicy", @@ -351,6 +364,7 @@ package main Type: "AWS::EKS::Cluster" Properties: { Name: Ref: "ClusterName" + Version: "1.19" RoleArn: "Fn::GetAtt": ["EKSIAMRole", "Arn"] ResourcesVpcConfig: { SecurityGroupIds: [{Ref: "ControlPlaneSecurityGroup"}] diff --git a/examples/aws-eks/cfn_template_eks_nodegroup.cue b/examples/aws-eks/cfn_template_eks_nodegroup.cue index 528f71c6..ab38c50f 100644 --- a/examples/aws-eks/cfn_template_eks_nodegroup.cue +++ b/examples/aws-eks/cfn_template_eks_nodegroup.cue @@ -3,55 +3,11 @@ package main #CFNTemplate: eksNodeGroup: { AWSTemplateFormatVersion: "2010-09-09" Description: "Amazon EKS - Node Group" - Metadata: "AWS::CloudFormation::Interface": ParameterGroups: [ - { - Label: default: "EKS Cluster" - Parameters: [ - "ClusterName", - "ClusterControlPlaneSecurityGroup", - ] - }, - { - Label: default: "Worker Node Configuration" - Parameters: [ - "NodeGroupName", - "NodeAutoScalingGroupMinSize", - "NodeAutoScalingGroupDesiredCapacity", - "NodeAutoScalingGroupMaxSize", - "NodeInstanceType", - "NodeImageIdSSMParam", - "NodeImageId", - "NodeVolumeSize", - // "KeyName", - "BootstrapArguments", - ] - }, - { - Label: default: "Worker Network Configuration" - Parameters: [ - "VpcId", - "Subnets", - ] - }, - ] Parameters: { - BootstrapArguments: { - Type: "String" - Default: "" - Description: "Arguments to pass to the bootstrap script. See files/bootstrap.sh in https://github.com/awslabs/amazon-eks-ami" - } - ClusterControlPlaneSecurityGroup: { - Type: "AWS::EC2::SecurityGroup::Id" - Description: "The security group of the cluster control plane." - } ClusterName: { Type: "String" Description: "The cluster name provided when the cluster was created. If it is incorrect, nodes will not be able to join the cluster." } - // KeyName: { - // Type: "AWS::EC2::KeyPair::KeyName" - // Description: "The EC2 Key Pair to allow SSH access to the instances" - // } NodeAutoScalingGroupDesiredCapacity: { Type: "Number" Default: 3 @@ -67,50 +23,17 @@ package main Default: 1 Description: "Minimum size of Node Group ASG." } - NodeGroupName: { - Type: "String" - Description: "Unique identifier for the Node Group." - } - NodeImageId: { - Type: "String" - Default: "" - Description: "(Optional) Specify your own custom image ID. This value overrides any AWS Systems Manager Parameter Store value specified above." - } - NodeImageIdSSMParam: { - Type: "AWS::SSM::Parameter::Value" - Default: "/aws/service/eks/optimized-ami/1.19/amazon-linux-2/recommended/image_id" - Description: "AWS Systems Manager Parameter Store parameter of the AMI ID for the worker node instances." - } NodeInstanceType: { Type: "String" Default: "t3.medium" ConstraintDescription: "Must be a valid EC2 instance type" Description: "EC2 instance type for the node instances" } - NodeVolumeSize: { - Type: "Number" - Default: 20 - Description: "Node volume size" - } Subnets: { Type: "List" Description: "The subnets where workers can be created." } - VpcId: { - Type: "AWS::EC2::VPC::Id" - Description: "The VPC of the worker instances" - } } - Conditions: HasNodeImageId: "Fn::Not": [ - { - "Fn::Equals": [ - { - Ref: "NodeImageId" - }, - "", - ] - }, - ] Resources: { NodeInstanceRole: { Type: "AWS::IAM::Role" @@ -137,175 +60,30 @@ package main Path: "/" } } - NodeInstanceProfile: { - Type: "AWS::IAM::InstanceProfile" + Nodegroup: { + Type: "AWS::EKS::Nodegroup" Properties: { - Path: "/" - Roles: [ - { - Ref: "NodeInstanceRole" - }, + ClusterName: Ref: "ClusterName" + NodeRole: "Fn::GetAtt": [ + "NodeInstanceRole", + "Arn", ] - } - } - NodeSecurityGroup: { - Type: "AWS::EC2::SecurityGroup" - Properties: { - GroupDescription: "Security group for all nodes in the cluster" - Tags: [ - { - Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" - Value: "owned" - }, - ] - VpcId: Ref: "VpcId" - } - } - NodeSecurityGroupIngress: { - Type: "AWS::EC2::SecurityGroupIngress" - DependsOn: "NodeSecurityGroup" - Properties: { - Description: "Allow node to communicate with each other" - FromPort: 0 - GroupId: Ref: "NodeSecurityGroup" - IpProtocol: "-1" - SourceSecurityGroupId: Ref: "NodeSecurityGroup" - ToPort: 65535 - } - } - ClusterControlPlaneSecurityGroupIngress: { - Type: "AWS::EC2::SecurityGroupIngress" - DependsOn: "NodeSecurityGroup" - Properties: { - Description: "Allow pods to communicate with the cluster API Server" - FromPort: 443 - GroupId: Ref: "ClusterControlPlaneSecurityGroup" - IpProtocol: "tcp" - SourceSecurityGroupId: Ref: "NodeSecurityGroup" - ToPort: 443 - } - } - ControlPlaneEgressToNodeSecurityGroup: { - Type: "AWS::EC2::SecurityGroupEgress" - DependsOn: "NodeSecurityGroup" - Properties: { - Description: "Allow the cluster control plane to communicate with worker Kubelet and pods" - DestinationSecurityGroupId: Ref: "NodeSecurityGroup" - FromPort: 1025 - GroupId: Ref: "ClusterControlPlaneSecurityGroup" - IpProtocol: "tcp" - ToPort: 65535 - } - } - ControlPlaneEgressToNodeSecurityGroupOn443: { - Type: "AWS::EC2::SecurityGroupEgress" - DependsOn: "NodeSecurityGroup" - Properties: { - Description: "Allow the cluster control plane to communicate with pods running extension API servers on port 443" - DestinationSecurityGroupId: Ref: "NodeSecurityGroup" - FromPort: 443 - GroupId: Ref: "ClusterControlPlaneSecurityGroup" - IpProtocol: "tcp" - ToPort: 443 - } - } - NodeSecurityGroupFromControlPlaneIngress: { - Type: "AWS::EC2::SecurityGroupIngress" - DependsOn: "NodeSecurityGroup" - Properties: { - Description: "Allow worker Kubelets and pods to receive communication from the cluster control plane" - FromPort: 1025 - GroupId: Ref: "NodeSecurityGroup" - IpProtocol: "tcp" - SourceSecurityGroupId: Ref: "ClusterControlPlaneSecurityGroup" - ToPort: 65535 - } - } - NodeSecurityGroupFromControlPlaneOn443Ingress: { - Type: "AWS::EC2::SecurityGroupIngress" - DependsOn: "NodeSecurityGroup" - Properties: { - Description: "Allow pods running extension API servers on port 443 to receive communication from cluster control plane" - FromPort: 443 - GroupId: Ref: "NodeSecurityGroup" - IpProtocol: "tcp" - SourceSecurityGroupId: Ref: "ClusterControlPlaneSecurityGroup" - ToPort: 443 - } - } - NodeLaunchConfig: { - Type: "AWS::AutoScaling::LaunchConfiguration" - Properties: { - AssociatePublicIpAddress: "true" - BlockDeviceMappings: [ - { - DeviceName: "/dev/xvda" - Ebs: { - DeleteOnTermination: true - VolumeSize: Ref: "NodeVolumeSize" - VolumeType: "gp2" - } - }, - ] - IamInstanceProfile: Ref: "NodeInstanceProfile" - ImageId: "Fn::If": [ - "HasNodeImageId", - { - Ref: "NodeImageId" - }, - { - Ref: "NodeImageIdSSMParam" - }, - ] - InstanceType: Ref: "NodeInstanceType" - // KeyName: Ref: "KeyName" - SecurityGroups: [ - { - Ref: "NodeSecurityGroup" - }, - ] - UserData: "Fn::Base64": "Fn::Sub": "#!/bin/bash\nset -o xtrace\n/etc/eks/bootstrap.sh ${ClusterName} ${BootstrapArguments}\n/opt/aws/bin/cfn-signal --exit-code $? \\\n --stack ${AWS::StackName} \\\n --resource NodeGroup \\\n --region ${AWS::Region}\n" - } - } - NodeGroup: { - Type: "AWS::AutoScaling::AutoScalingGroup" - Properties: { - DesiredCapacity: Ref: "NodeAutoScalingGroupDesiredCapacity" - LaunchConfigurationName: Ref: "NodeLaunchConfig" - MaxSize: Ref: "NodeAutoScalingGroupMaxSize" - MinSize: Ref: "NodeAutoScalingGroupMinSize" - Tags: [ - { - Key: "Name" - PropagateAtLaunch: "true" - Value: "Fn::Sub": "${ClusterName}-${NodeGroupName}-Node" - }, - { - Key: "Fn::Sub": "kubernetes.io/cluster/${ClusterName}" - PropagateAtLaunch: "true" - Value: "owned" - }, - ] - VPCZoneIdentifier: Ref: "Subnets" - } - UpdatePolicy: AutoScalingRollingUpdate: { - MaxBatchSize: "1" - MinInstancesInService: Ref: "NodeAutoScalingGroupDesiredCapacity" - PauseTime: "PT5M" + ScalingConfig: { + MaxSize: Ref: "NodeAutoScalingGroupMaxSize" + MinSize: Ref: "NodeAutoScalingGroupMinSize" + DesiredSize: Ref: "NodeAutoScalingGroupDesiredCapacity" + } + InstanceTypes: [{Ref: "NodeInstanceType"}] + AmiType: "AL2_x86_64" + Subnets: Ref: "Subnets" } } } - Outputs: { - NodeInstanceRole: { - Description: "The node instance role" - Value: "Fn::GetAtt": [ - "NodeInstanceRole", - "Arn", - ] - } - NodeSecurityGroup: { - Description: "The security group for the node group" - Value: Ref: "NodeSecurityGroup" - } + Outputs: NodeInstanceRole: { + Description: "The node instance role" + Value: "Fn::GetAtt": [ + "NodeInstanceRole", + "Arn", + ] } } diff --git a/examples/aws-eks/cue.mod/module.cue b/examples/aws-eks/cue.mod/module.cue new file mode 100644 index 00000000..f8af9cef --- /dev/null +++ b/examples/aws-eks/cue.mod/module.cue @@ -0,0 +1 @@ +module: "" diff --git a/examples/aws-eks/infrastructure.cue b/examples/aws-eks/infrastructure.cue index 1083e9a2..b2a4bf95 100644 --- a/examples/aws-eks/infrastructure.cue +++ b/examples/aws-eks/infrastructure.cue @@ -8,11 +8,10 @@ import ( ) #Infrastructure: { - awsConfig: aws.#Config - namePrefix: *"dagger-example-" | string - // Cluster size is 1 for example (to limit resources) - workerNodeCapacity: *1 | >1 - workerNodeInstanceType: *"t3.small" | string + awsConfig: aws.#Config + namePrefix: *"" | string + workerNodeCapacity: *3 | >=1 + workerNodeInstanceType: *"t3.medium" | string let clusterName = "\(namePrefix)eks-cluster" @@ -21,6 +20,7 @@ import ( source: json.Marshal(#CFNTemplate.eksControlPlane) stackName: "\(namePrefix)eks-controlplane" neverUpdate: true + timeout: 30 parameters: ClusterName: clusterName } @@ -29,14 +29,12 @@ import ( source: json.Marshal(#CFNTemplate.eksNodeGroup) stackName: "\(namePrefix)eks-nodegroup" neverUpdate: true + timeout: 30 parameters: { ClusterName: clusterName - ClusterControlPlaneSecurityGroup: eksControlPlane.outputs.DefaultSecurityGroup NodeAutoScalingGroupDesiredCapacity: 1 NodeAutoScalingGroupMaxSize: NodeAutoScalingGroupDesiredCapacity + 1 - NodeGroupName: "\(namePrefix)eks-nodegroup" NodeInstanceType: workerNodeInstanceType - VpcId: eksControlPlane.outputs.VPC Subnets: eksControlPlane.outputs.SubnetIds } } diff --git a/examples/aws-eks/main.cue b/examples/aws-eks/main.cue index d126a729..756018a9 100644 --- a/examples/aws-eks/main.cue +++ b/examples/aws-eks/main.cue @@ -18,4 +18,8 @@ awsConfig: aws.#Config & { // base config can be changed (number of EC2 instances, types, etc...) infra: #Infrastructure & { "awsConfig": awsConfig + namePrefix: "dagger-example-" + // Cluster size is 1 for the example purpose + workerNodeCapacity: 1 + workerNodeInstanceType: "t3.small" } From ea02b579d663ffac30ef673e8a4d1d183d602709 Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Thu, 18 Mar 2021 15:51:56 -0700 Subject: [PATCH 4/8] stdlib: implemented aws/eks Signed-off-by: Sam Alba --- stdlib/aws/eks/code.cue | 26 ++++++++++++++++++ stdlib/aws/eks/eks.cue | 59 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 stdlib/aws/eks/code.cue create mode 100644 stdlib/aws/eks/eks.cue diff --git a/stdlib/aws/eks/code.cue b/stdlib/aws/eks/code.cue new file mode 100644 index 00000000..9a172275 --- /dev/null +++ b/stdlib/aws/eks/code.cue @@ -0,0 +1,26 @@ +package eks + +#Code: #""" + [ -e /cache/bin/kubectl ] || { + curl -sfL https://dl.k8s.io/v1.19.9/bin/linux/amd64/kubectl -o /cache/bin/kubectl && chmod +x /cache/bin/kubectl + } + + export KUBECONFIG=/kubeconfig + export PATH="$PATH:/cache/bin" + + # Generate a kube configuration + aws eks update-kubeconfig --name "$EKS_CLUSTER" + + # Figure out the kubernetes username + CONTEXT="$(kubectl config current-context)" + USER="$(kubectl config view -o json | \ + jq -r ".contexts[] | select(.name==\"$CONTEXT\") | .context.user")" + + # Grab a kubernetes access token + ACCESS_TOKEN="$(aws eks get-token --cluster-name "$EKS_CLUSTER" | \ + jq -r .status.token)" + + # Remove the user config and replace it with the token + kubectl config unset "users.${USER}" + kubectl config set-credentials "$USER" --token "$ACCESS_TOKEN" + """# diff --git a/stdlib/aws/eks/eks.cue b/stdlib/aws/eks/eks.cue new file mode 100644 index 00000000..02635030 --- /dev/null +++ b/stdlib/aws/eks/eks.cue @@ -0,0 +1,59 @@ +package eks + +import ( + "dagger.io/llb" + "dagger.io/aws" +) + +// KubeConfig config outputs a valid kube-auth-config for kubectl client +#KubeConfig: { + // AWS Config + config: aws.#Config + + // EKS cluster name + clusterName: string + + // kubeconfig is the generated kube configuration file + kubeconfig: { + string + + #compute: [ + llb.#Load & { + from: aws.#CLI + }, + llb.#WriteFile & { + dest: "/entrypoint.sh" + content: #Code + }, + llb.#Exec & { + always: true + args: [ + "/bin/bash", + "--noprofile", + "--norc", + "-eo", + "pipefail", + "/entrypoint.sh", + ] + env: { + AWS_CONFIG_FILE: "/cache/aws/config" + AWS_ACCESS_KEY_ID: config.accessKey + AWS_SECRET_ACCESS_KEY: config.secretKey + AWS_DEFAULT_REGION: config.region + AWS_REGION: config.region + AWS_DEFAULT_OUTPUT: "json" + AWS_PAGER: "" + EKS_CLUSTER: clusterName + } + mount: { + "/cache/aws": "cache" + "/cache/bin": "cache" + } + }, + llb.#Export & { + source: "/kubeconfig" + format: "string" + }, + ] + } +} From 54251f88b431e790374957e6dcb820584715468a Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Thu, 18 Mar 2021 15:53:26 -0700 Subject: [PATCH 5/8] stdlib: share aws config cli Signed-off-by: Sam Alba --- stdlib/aws/aws.cue | 21 +++++++++++++++++++- stdlib/aws/cloudformation/cloudformation.cue | 9 ++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/stdlib/aws/aws.cue b/stdlib/aws/aws.cue index a9d8bc20..4f6bbf6c 100644 --- a/stdlib/aws/aws.cue +++ b/stdlib/aws/aws.cue @@ -1,7 +1,12 @@ package aws -import "dagger.io/dagger" +import ( + "dagger.io/dagger" + "dagger.io/llb" + "dagger.io/alpine" +) +// Base AWS Config #Config: { // AWS region region: string @@ -10,3 +15,17 @@ import "dagger.io/dagger" // AWS secret key secretKey: dagger.#Secret } + +// Re-usable aws-cli component +#CLI: { + #compute: [ + llb.#Load & { + from: alpine.#Image & { + package: bash: "=5.1.0-r0" + package: jq: "=1.6-r1" + package: curl: "=7.74.0-r1" + package: "aws-cli": "=1.18.177-r0" + } + }, + ] +} diff --git a/stdlib/aws/cloudformation/cloudformation.cue b/stdlib/aws/cloudformation/cloudformation.cue index 39e1f6bb..2b504895 100644 --- a/stdlib/aws/cloudformation/cloudformation.cue +++ b/stdlib/aws/cloudformation/cloudformation.cue @@ -3,9 +3,8 @@ package cloudformation import ( "encoding/json" - "dagger.io/alpine" - "dagger.io/aws" "dagger.io/llb" + "dagger.io/aws" ) // AWS CloudFormation Stack @@ -50,11 +49,7 @@ import ( outputs: { #compute: [ llb.#Load & { - from: alpine.#Image & { - package: bash: "=5.1.0-r0" - package: jq: "=1.6-r1" - package: "aws-cli": "=1.18.177-r0" - } + from: aws.#CLI }, llb.#Mkdir & { path: "/src" From abdcb7e093db57e7d4942a580b981f5bdf13f2ff Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Thu, 18 Mar 2021 15:53:55 -0700 Subject: [PATCH 6/8] added kubeconfig code in the example + updated readme Signed-off-by: Sam Alba --- examples/aws-eks/README.md | 5 ++++- examples/aws-eks/infrastructure.cue | 18 +++++++++--------- examples/aws-eks/main.cue | 6 ++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/examples/aws-eks/README.md b/examples/aws-eks/README.md index ae70f397..dfc50a8b 100644 --- a/examples/aws-eks/README.md +++ b/examples/aws-eks/README.md @@ -1,9 +1,12 @@ # Kubernetes on AWS (EKS) +This example creates a new EKS cluster and outputs its corresponding kubeconfig + ## How to run ```sh dagger compute . \ --input-string awsConfig.accessKey="MY_AWS_ACCESS_KEY" \ - --input-string awsConfig.secretKey="MY_AWS_SECRET_KEY" + --input-string awsConfig.secretKey="MY_AWS_SECRET_KEY" \ + | jq -j '.kubeconfig.kubeconfig' > kubeconfig ``` diff --git a/examples/aws-eks/infrastructure.cue b/examples/aws-eks/infrastructure.cue index b2a4bf95..2e43c7d5 100644 --- a/examples/aws-eks/infrastructure.cue +++ b/examples/aws-eks/infrastructure.cue @@ -13,23 +13,23 @@ import ( workerNodeCapacity: *3 | >=1 workerNodeInstanceType: *"t3.medium" | string - let clusterName = "\(namePrefix)eks-cluster" + clusterName: "\(namePrefix)eks-cluster" eksControlPlane: cloudformation.#Stack & { - config: awsConfig - source: json.Marshal(#CFNTemplate.eksControlPlane) - stackName: "\(namePrefix)eks-controlplane" + config: awsConfig + source: json.Marshal(#CFNTemplate.eksControlPlane) + stackName: "\(namePrefix)eks-controlplane" neverUpdate: true - timeout: 30 + timeout: 30 parameters: ClusterName: clusterName } eksNodeGroup: cloudformation.#Stack & { - config: awsConfig - source: json.Marshal(#CFNTemplate.eksNodeGroup) - stackName: "\(namePrefix)eks-nodegroup" + config: awsConfig + source: json.Marshal(#CFNTemplate.eksNodeGroup) + stackName: "\(namePrefix)eks-nodegroup" neverUpdate: true - timeout: 30 + timeout: 30 parameters: { ClusterName: clusterName NodeAutoScalingGroupDesiredCapacity: 1 diff --git a/examples/aws-eks/main.cue b/examples/aws-eks/main.cue index 756018a9..e605701f 100644 --- a/examples/aws-eks/main.cue +++ b/examples/aws-eks/main.cue @@ -2,6 +2,7 @@ package main import ( "dagger.io/aws" + "dagger.io/aws/eks" ) // Fill using: @@ -23,3 +24,8 @@ infra: #Infrastructure & { workerNodeCapacity: 1 workerNodeInstanceType: "t3.small" } + +kubeconfig: eks.#KubeConfig & { + config: awsConfig + clusterName: infra.clusterName +} From 13fa94706259cf1303303013adc7f290a5ab5495 Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Thu, 18 Mar 2021 15:54:53 -0700 Subject: [PATCH 7/8] stdlib: cue fmt Signed-off-by: Sam Alba --- examples/aws-eks/cue.mod/module.cue | 1 - examples/aws-eks/cue.mod/pkg/dagger.io | 1 - stdlib/aws/cloudformation/cloudformation.cue | 90 ++++++++++---------- stdlib/aws/eks/code.cue | 36 ++++---- 4 files changed, 62 insertions(+), 66 deletions(-) delete mode 100644 examples/aws-eks/cue.mod/module.cue delete mode 120000 examples/aws-eks/cue.mod/pkg/dagger.io diff --git a/examples/aws-eks/cue.mod/module.cue b/examples/aws-eks/cue.mod/module.cue deleted file mode 100644 index f8af9cef..00000000 --- a/examples/aws-eks/cue.mod/module.cue +++ /dev/null @@ -1 +0,0 @@ -module: "" diff --git a/examples/aws-eks/cue.mod/pkg/dagger.io b/examples/aws-eks/cue.mod/pkg/dagger.io deleted file mode 120000 index 1aafa4de..00000000 --- a/examples/aws-eks/cue.mod/pkg/dagger.io +++ /dev/null @@ -1 +0,0 @@ -../../../../stdlib \ No newline at end of file diff --git a/stdlib/aws/cloudformation/cloudformation.cue b/stdlib/aws/cloudformation/cloudformation.cue index 2b504895..43d3e52f 100644 --- a/stdlib/aws/cloudformation/cloudformation.cue +++ b/stdlib/aws/cloudformation/cloudformation.cue @@ -46,51 +46,49 @@ import ( outputs: [string]: string - outputs: { - #compute: [ - llb.#Load & { - from: aws.#CLI - }, - llb.#Mkdir & { - path: "/src" - }, - for dest, content in #files { - llb.#WriteFile & { - "dest": dest - "content": content + outputs: #compute: [ + llb.#Load & { + from: aws.#CLI + }, + llb.#Mkdir & { + path: "/src" + }, + for dest, content in #files { + llb.#WriteFile & { + "dest": dest + "content": content + } + }, + llb.#Exec & { + args: [ + "/bin/bash", + "--noprofile", + "--norc", + "-eo", + "pipefail", + "/entrypoint.sh", + ] + env: { + AWS_CONFIG_FILE: "/cache/aws/config" + AWS_ACCESS_KEY_ID: config.accessKey + AWS_SECRET_ACCESS_KEY: config.secretKey + AWS_DEFAULT_REGION: config.region + AWS_REGION: config.region + AWS_DEFAULT_OUTPUT: "json" + AWS_PAGER: "" + if neverUpdate { + NEVER_UPDATE: "true" } - }, - llb.#Exec & { - args: [ - "/bin/bash", - "--noprofile", - "--norc", - "-eo", - "pipefail", - "/entrypoint.sh", - ] - env: { - AWS_CONFIG_FILE: "/cache/aws/config" - AWS_ACCESS_KEY_ID: config.accessKey - AWS_SECRET_ACCESS_KEY: config.secretKey - AWS_DEFAULT_REGION: config.region - AWS_REGION: config.region - AWS_DEFAULT_OUTPUT: "json" - AWS_PAGER: "" - if neverUpdate { - NEVER_UPDATE: "true" - } - STACK_NAME: stackName - TIMEOUT: "\(timeout)" - ON_FAILURE: onFailure - } - dir: "/src" - mount: "/cache/aws": "cache" - }, - llb.#Export & { - source: "/outputs.json" - format: "json" - }, - ] - } + STACK_NAME: stackName + TIMEOUT: "\(timeout)" + ON_FAILURE: onFailure + } + dir: "/src" + mount: "/cache/aws": "cache" + }, + llb.#Export & { + source: "/outputs.json" + format: "json" + }, + ] } diff --git a/stdlib/aws/eks/code.cue b/stdlib/aws/eks/code.cue index 9a172275..9cb1a630 100644 --- a/stdlib/aws/eks/code.cue +++ b/stdlib/aws/eks/code.cue @@ -1,26 +1,26 @@ package eks #Code: #""" - [ -e /cache/bin/kubectl ] || { - curl -sfL https://dl.k8s.io/v1.19.9/bin/linux/amd64/kubectl -o /cache/bin/kubectl && chmod +x /cache/bin/kubectl - } + [ -e /cache/bin/kubectl ] || { + curl -sfL https://dl.k8s.io/v1.19.9/bin/linux/amd64/kubectl -o /cache/bin/kubectl && chmod +x /cache/bin/kubectl + } - export KUBECONFIG=/kubeconfig - export PATH="$PATH:/cache/bin" + export KUBECONFIG=/kubeconfig + export PATH="$PATH:/cache/bin" - # Generate a kube configuration - aws eks update-kubeconfig --name "$EKS_CLUSTER" + # Generate a kube configuration + aws eks update-kubeconfig --name "$EKS_CLUSTER" - # Figure out the kubernetes username - CONTEXT="$(kubectl config current-context)" - USER="$(kubectl config view -o json | \ - jq -r ".contexts[] | select(.name==\"$CONTEXT\") | .context.user")" + # Figure out the kubernetes username + CONTEXT="$(kubectl config current-context)" + USER="$(kubectl config view -o json | \ + jq -r ".contexts[] | select(.name==\"$CONTEXT\") | .context.user")" - # Grab a kubernetes access token - ACCESS_TOKEN="$(aws eks get-token --cluster-name "$EKS_CLUSTER" | \ - jq -r .status.token)" + # Grab a kubernetes access token + ACCESS_TOKEN="$(aws eks get-token --cluster-name "$EKS_CLUSTER" | \ + jq -r .status.token)" - # Remove the user config and replace it with the token - kubectl config unset "users.${USER}" - kubectl config set-credentials "$USER" --token "$ACCESS_TOKEN" - """# + # Remove the user config and replace it with the token + kubectl config unset "users.${USER}" + kubectl config set-credentials "$USER" --token "$ACCESS_TOKEN" + """# From dd5e5684b25c419587c1da9b3351c1351e982e8a Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Thu, 18 Mar 2021 16:26:38 -0700 Subject: [PATCH 8/8] stdlib: moved kubeconfig to #Secret Signed-off-by: Sam Alba --- stdlib/aws/eks/eks.cue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/aws/eks/eks.cue b/stdlib/aws/eks/eks.cue index 02635030..58eae8c5 100644 --- a/stdlib/aws/eks/eks.cue +++ b/stdlib/aws/eks/eks.cue @@ -15,7 +15,7 @@ import ( // kubeconfig is the generated kube configuration file kubeconfig: { - string + dagger.#Secret #compute: [ llb.#Load & {