AWSTemplateFormatVersion: '2010-09-09' Parameters: VPCName: Description: The name of the VPC being created. Type: String Default: "FSxONTAP-EKS-VPC" ## FSxN Parameters StorageCapacity: Default: 3072 Description: Specify the storage capacity of the file system being created, in gibibytes. Minimum 1024 GiB; Maximum 192 TiB. Type: Number FSxAllowedCIDR: Description: Specify the CIDR block that is allowed access to FSx for NetApp ONTAP file system. Type: String Default: "0.0.0.0/0" ThroughputCapacity: Description: Sets the throughput capacity for the file system that you're creating. Valid values are 512, 1024, and 2048 MBps. ConstraintDescription: Valid values are 512, 1024, and 2048 MBps. AllowedValues: [128, 512, 1024, 2048] Type: Number Default: 128 WeeklyMaintenanceTime: Description: Specify the preferred start time to perform weekly maintenance, formatted d:HH:MM in the UTC time zone Default: '7:01:00' Type: String RootVolumeSecurityStyle: Description: The security style of the root volume of the SVM. Specify one of the following values, UNIX, NTFS or MIXED. Type: String Default: UNIX AllowedValues: ["UNIX", "NTFS", "MIXED"] ## EC2 Parameters ## KeyName: Description: Name of an existing EC2 KeyPair to enable SSH access to the Linux instance Type: 'AWS::EC2::KeyPair::KeyName' ConstraintDescription: must be the name of an existing EC2 KeyPair. Default: ee-default-keypair LatestWindowsAmiId: Description: Do Not modify the below default value Type: 'AWS::SSM::Parameter::Value' Default: /aws/service/ami-windows-latest/Windows_Server-2019-English-Full-Base LatestLinuxAmiId: Description: Do Not modify the below default value Type: 'AWS::SSM::Parameter::Value' Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 ## Cloud 9 Environments ## Cloud9EnvironmentName: Description: How the name appears in the console Type: String Default: eks-fsx-workshop ClientInstanceType: Description: The type of instance to connect to the environment Type: String Default: c4.xlarge Cloud9OwnerArn: Description: The Amazon Resource Name (ARN) of the environment owner. This ARN can be the ARN of any AWS Identity and Access Management principal. If this value is not specified, the ARN defaults to this environment's creator. Type: String Default: none Mappings: SubnetConfig: VPC: CIDR: "10.0.0.0/16" Private1: CIDR: "10.0.0.0/24" Private2: CIDR: "10.0.1.0/24" Public1: CIDR: "10.0.100.0/24" Public2: CIDR: "10.0.101.0/24" # This mapping accounts for the scenario when certain AZs # are not available to use (this differs on a per account # per customer basis). E.g., if the 'b' AZ is not available # in a specific region in one's account then updating the # list contained in the mapping below here will allow a # different AZ to be chosen. AZRegions: us-east-1: AZs: ["a", "b"] us-east-2: AZs: ["a", "b"] us-west-1: AZs: ["a", "b"] us-west-2: AZs: ["a", "b"] ap-northeast-1: AZs: ["a", "b"] ap-northeast-2: AZs: ["a", "b"] ap-northeast-3: AZs: ["a", "b"] ap-east-1: AZs: ["a", "b"] ap-south-1: AZs: ["a", "b"] ap-southeast-1: AZs: ["a", "b"] ap-southeast-2: AZs: ["a", "b"] ap-southeast-3: AZs: ["a", "b"] ca-central-1: AZs: ["a", "b"] eu-central-1: AZs: ["a", "b"] eu-west-1: AZs: ["a", "b"] eu-west-2: AZs: ["a", "b"] eu-west-3: AZs: ["a", "b"] eu-south-1: AZs: ["a", "b"] eu-north-1: AZs: ["a", "b"] sa-east-1: AZs: ["a", "b"] af-south-1: AZs: ["a", "b"] me-south-1: AZs: ["a", "b"] Conditions: Cloud9OwnerArnNotProvided: !Equals - !Ref Cloud9OwnerArn - "none" Resources: ################################################################ ################################################################ ######################VPC and Subnets Creation################## ################################################################ ################################################################ VPC: Type: "AWS::EC2::VPC" Properties: EnableDnsSupport: "true" EnableDnsHostnames: "true" CidrBlock: Fn::FindInMap: - "SubnetConfig" - "VPC" - "CIDR" Tags: - Key: "Name" Value: !Ref 'VPCName' PrivateSubnet1: Type: "AWS::EC2::Subnet" Properties: VpcId: Ref: "VPC" AvailabilityZone: Fn::Sub: - "${AWS::Region}${AZ}" - AZ: !Select [ 0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] CidrBlock: Fn::FindInMap: - "SubnetConfig" - "Private1" - "CIDR" Tags: - Key: "Name" Value: !Join - '' - - !Ref "VPCName" - '-private-' - !Select [ 0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] PrivateSubnet2: Type: "AWS::EC2::Subnet" Properties: VpcId: Ref: "VPC" AvailabilityZone: Fn::Sub: - "${AWS::Region}${AZ}" - AZ: !Select [ 1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] CidrBlock: Fn::FindInMap: - "SubnetConfig" - "Private2" - "CIDR" Tags: - Key: "Name" Value: !Join - '' - - !Ref "VPCName" - '-private-' - !Select [ 1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] PublicSubnet1: Type: "AWS::EC2::Subnet" Properties: VpcId: Ref: "VPC" AvailabilityZone: Fn::Sub: - "${AWS::Region}${AZ}" - AZ: !Select [ 0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] CidrBlock: Fn::FindInMap: - "SubnetConfig" - "Public1" - "CIDR" MapPublicIpOnLaunch: true Tags: - Key: "Name" Value: !Join - '' - - !Ref "VPCName" - '-public-' - !Select [ 0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] PublicSubnet2: Type: "AWS::EC2::Subnet" Properties: VpcId: Ref: "VPC" AvailabilityZone: Fn::Sub: - "${AWS::Region}${AZ}" - AZ: !Select [ 1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] CidrBlock: Fn::FindInMap: - "SubnetConfig" - "Public2" - "CIDR" MapPublicIpOnLaunch: true Tags: - Key: "Name" Value: !Join - '' - - !Ref "VPCName" - '-public-' - !Select [ 1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs" ] ] InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub "${VPCName}-ITG" InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC NatGateway1EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway2EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc NatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnet1 NatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnet2 PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${VPCName} Public Routes DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet2 PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${VPCName} Private Routes (AZ1) DefaultPrivateRoute1: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 PrivateSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable1 SubnetId: !Ref PrivateSubnet1 PrivateSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable1 SubnetId: !Ref PrivateSubnet2 ################################################ ###### FSx for NetApp ONTAP #################### ################################################ FSxONTAPSecurityGroup: Type: AWS::EC2::SecurityGroup DependsOn: VPC Properties: VpcId: !Ref VPC GroupDescription: Security Group for FSx for NetApp ONTAP Storage Access SecurityGroupIngress: - IpProtocol: icmp FromPort: -1 ToPort: -1 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 111 ToPort: 111 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 135 ToPort: 135 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 139 ToPort: 139 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 161 ToPort: 161 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 162 ToPort: 162 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 445 ToPort: 445 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 635 ToPort: 635 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 749 ToPort: 749 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 2049 ToPort: 2049 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 3260 ToPort: 3260 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 4045 ToPort: 4045 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 4046 ToPort: 4046 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 11104 ToPort: 11104 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: tcp FromPort: 11105 ToPort: 11105 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 111 ToPort: 111 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 135 ToPort: 135 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 137 ToPort: 137 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 139 ToPort: 139 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 161 ToPort: 161 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 162 ToPort: 162 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 635 ToPort: 635 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 2049 ToPort: 2049 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 4045 ToPort: 4045 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 4046 ToPort: 4046 CidrIp: !Ref FSxAllowedCIDR - IpProtocol: udp FromPort: 4049 ToPort: 4049 CidrIp: !Ref FSxAllowedCIDR ## Secret Manager SMFsxAdminPassword: Type: AWS::SecretsManager::Secret Properties: Description: FSx for NetApp ONTAP filesystem password for username fsxadmin Name: !Sub "${AWS::StackName}-FsxAdminPassword" #SecretString: !Sub '{"username":"fsxadmin","password":${FsxAdminPassword}}' GenerateSecretString: SecretStringTemplate: '{"username": "fsxadmin"}' GenerateStringKey: "password" PasswordLength: 12 ExcludeCharacters: "\"@/\\" ExcludePunctuation: true Tags: - Key: "Name" Value: "OntapFileSystem_filesystem_Password" SMSVMAdminPassword: Type: AWS::SecretsManager::Secret Properties: Description: SVM Admin Password for username vsadmin Name: !Sub "${AWS::StackName}-SVMAdminPassword" #SecretString: !Sub '{"username":"vsadmin","password": ${SvmAdminPassword}}' GenerateSecretString: SecretStringTemplate: '{"username": "vsadmin"}' GenerateStringKey: "password" PasswordLength: 12 ExcludeCharacters: "\"@/\\" ExcludePunctuation: true Tags: - Key: "Name" Value: "OntapFileSystem_SVM_Password" ## Create IAM Role and Policy to be able to retrieve Secrets Manager SecretsManagerIAMPolicy: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: 'TridentIAMPolicy' PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'secretsmanager:GetSecretValue' - 'secretsmanager:DescribeSecret' Resource: - !Ref SMFsxAdminPassword - !Ref SMSVMAdminPassword FSxONTAP: Type: AWS::FSx::FileSystem DependsOn: PrivateSubnet1 Properties: FileSystemType: ONTAP StorageCapacity: !Ref StorageCapacity StorageType: SSD SecurityGroupIds: - !GetAtt FSxONTAPSecurityGroup.GroupId SubnetIds: - !Ref PrivateSubnet1 ## Private Subnets - !Ref PrivateSubnet2 OntapConfiguration: AutomaticBackupRetentionDays: 3 DailyAutomaticBackupStartTime: "01:00" DeploymentType: MULTI_AZ_1 DiskIopsConfiguration: Mode: AUTOMATIC PreferredSubnetId: !Ref PrivateSubnet1 RouteTableIds: #!Split #- !GetAtt FSxONTAPRouteTable.RouteTableId - !Ref PrivateRouteTable1 - !Ref PublicRouteTable ThroughputCapacity: !Ref ThroughputCapacity WeeklyMaintenanceStartTime: !Ref WeeklyMaintenanceTime FsxAdminPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref SMFsxAdminPassword, ':SecretString:password}}' ]] Tags: - Key: "Name" Value: "OntapFileSystem_MAZ" SVM1: Type: AWS::FSx::StorageVirtualMachine DependsOn: FSxONTAP Properties: FileSystemId: !Ref FSxONTAP Name: SVM1 RootVolumeSecurityStyle: !Ref RootVolumeSecurityStyle SvmAdminPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref SMSVMAdminPassword, ':SecretString:password}}' ]] ################################################ ######## EC2 Instance ######################## ############################################### BastionHostSG: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VPC GroupDescription: Security Group for EC2 Bastion Host Linux amd Windows SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 3389 ToPort: 3389 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 EC2InstanceProfile: Properties: Path: / Roles: - Ref: EC2InstanceRole Type: 'AWS::IAM::InstanceProfile' EC2InstanceRole: Type: 'AWS::IAM::Role' DeletionPolicy: Delete Properties: RoleName: eks-fsx-workshop-admin AssumeRolePolicyDocument: Statement: - Effect: Allow Action: - 'sts:AssumeRole' Principal: Service: - ec2.amazonaws.com - ssm.amazonaws.com - lambda.amazonaws.com AWS: - !Sub "arn:aws:iam::${AWS::AccountId}:root" - !Sub "arn:aws:iam::${AWS::AccountId}:user/EEOverlord" - !Sub "arn:aws:sts::${AWS::AccountId}:assumed-role/TeamRole/MasterKey" #- !Sub "arn:aws:iam::${AWS::AccountId}:user/haofeif" Version: '2012-10-17' ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM - arn:aws:iam::aws:policy/AmazonEC2FullAccess - arn:aws:iam::aws:policy/job-function/SystemAdministrator EC2InstanceRolePolicy: Type: 'AWS::IAM::Policy' DeletionPolicy: Delete Properties: PolicyName: 'Fn::Join': - '' - - EC2-client- - Ref: 'AWS::StackName' Roles: - Ref: EC2InstanceRole PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: 'secretsmanager:*' Resource: '*' - Effect: Allow Action: - 's3:Get*' - 's3:List*' Resource: '*' - Effect: Allow Action: - 'eks:*' - 'fsx:*' - 'cloud9:*' - 'iam:List*' - 'iam:Get*' - 'iam:Tag*' - 'iam:Untag*' - 'iam:Add*' - 'iam:CreateOpenIDConnectProvider' - 'iam:PassRole' - 'iam:DeleteOpenIDConnectProvider' - 'iam:CreateRole' - 'iam:CreateInstanceProfile' - 'iam:CreateServiceLinkedRole' - 'iam:CreatePolicy*' - 'iam:PutRolePolicy' - 'iam:DeleteRole' - 'iam:DeleteRolePolicy' - 'iam:DeleteServiceLinkedRole' - 'iam:DeleteInstanceProfile' - 'iam:DeletePolicy*' - 'iam:Detach*' - 'iam:RemoveClientIDFromOpenIDConnectProvider' - 'iam:RemoveRoleFromInstanceProfile' - 'iam:UpdateOpenIDConnectProvider*' - 'iam:UpdateRole*' - 'iam:Attach*' - 'cloudformation:*' - 'ssm:*' - 'logs:*' Resource: '*' AdminSecret: Type: 'AWS::SecretsManager::Secret' Properties: Description: Admin Password for workshop. GenerateSecretString: PasswordLength: 12 ExcludeCharacters: "\"@/\\" ExcludePunctuation: true WindowsInstance: Type: 'AWS::EC2::Instance' DependsOn: PublicSubnet2 Properties: ImageId: Ref: LatestWindowsAmiId InstanceType: !Ref ClientInstanceType #KeyName: # Ref: KeyName SecurityGroupIds: - !GetAtt BastionHostSG.GroupId SubnetId: !Ref PublicSubnet2 IamInstanceProfile: Ref: EC2InstanceProfile Tags: - Key: Name Value: Workshop Windows Instance 1 UserData: Fn::Base64: !Sub | # disable ie security (windows) function Disable-ieESC { $AdminKey = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}" $UserKey = "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}" Set-ItemProperty -Path $AdminKey -Name "IsInstalled" -Value 0 Set-ItemProperty -Path $UserKey -Name "IsInstalled" -Value 0 Stop-Process -Name Explorer Write-Host "IE Enhanced Security Configuration (ESC) has been disabled." -ForegroundColor Green } Disable-ieESC # install DiskSpd (windows) $path = "C:\Tools\DiskSpd-2.0.21a" $url = "https://github.com/microsoft/diskspd/releases/download/v2.0.21a/DiskSpd.zip" $destination = "C:\Tools\DiskSpd-2.0.21a.zip" $download = New-Object -Typename System.Net.WebClient New-Item -Type Directory -Path $path $download.DownloadFile($url,$destination) $extract = New-Object -ComObject Shell.Application $files = $extract.Namespace($destination).Items() $extract.NameSpace($path).CopyHere($files) WindowsBootstrappingTasks: Type: AWS::SSM::Document DependsOn: WindowsInstance Properties: DocumentType: Command Content: schemaVersion: "2.2" description: Administration Tasks parameters: AdminPassword: type: String description: (Required)Admin Password of the Secret Generated mainSteps: - action: aws:runPowerShellScript name: 1changeadminpassword inputs: runCommand: - echo "Printing Secrets Manager ARN:{{ AdminPassword }}" - $password = (Get-SECSecretValue -SecretId {{ AdminPassword }}).SecretString - Set-LocalUser -Name Administrator -Password (ConvertTo-SecureString -AsPlainText “$password” -Force) - Set-ItemProperty -Path ‘HKLM:\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}’ -Name IsInstalled -Value 0 -Force - action: aws:runPowerShellScript name: 2installawscli inputs: runCommand: #- Invoke-WebRequest "https://awscli.amazonaws.com/AWSCLIV2.msi" -OutFile c:\AWSCLIV2.msi #- msiexec.exe /i "c:\AWSCLIV2.msi" /qn - Invoke-WebRequest https://s3.amazonaws.com/aws-cli/AWSCLI64.msi -OutFile c:\AWSCLI64.msi - msiexec.exe /i "c:\AWSCLI64.msi" /qn #- action: aws:runPowerShellScript # name: 3installchrome # inputs: # runCommand: # - Invoke-WebRequest http://dl.google.com/chrome/install/375.126/chrome_installer.exe -OutFile c:\chrome-installer.exe # - Start-Process -FilePath c:\chrome-installer.exe -Args ‘/silent /install’ -Verb RunAs - action: aws:runPowerShellScript name: 4installkubectl inputs: runCommand: # Download Chocolatey as the Package Management Tool - Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) # install kubectl, helm and Visual Studio Code Chrome - choco install kubernetes-cli vscode googlechrome -y # install helm v3.8 - choco install kubernetes-helm --version=3.8.2 -y # install python3 - choco install python3 --pre -y # install git - choco install git.install --version=2.19.1 -y - action: aws:runPowerShellScript name: 6clonerepo inputs: runCommand: - cd 'C:\Program Files\Git\cmd' - New-Item "C:\Users\Administrator\Desktop\eks-fsx-workshop" -ItemType Directory - .\git clone https://github.com/aws-samples/eks-fsx-workshop.git C:\Users\Administrator\Desktop\eks-fsx-workshop Association: Type: AWS::SSM::Association Properties: Name: !Ref WindowsBootstrappingTasks Parameters: AdminPassword: [!Ref AdminSecret] Targets: - Key: InstanceIds Values: [ !Ref WindowsInstance ] LinuxInstance: Type: 'AWS::EC2::Instance' DependsOn: - PublicSubnet2 - PublicSubnet1 - PrivateSubnet1 - PrivateSubnet2 Properties: ImageId: Ref: LatestLinuxAmiId KeyName: Ref: KeyName InstanceType: !Ref ClientInstanceType IamInstanceProfile: !Ref EC2InstanceProfile SecurityGroupIds: - !GetAtt BastionHostSG.GroupId SubnetId: Ref: PublicSubnet2 Tags: - Key: Name Value: Workshop Linux Instance 1 UserData: Fn::Base64: !Sub | #!/bin/bash yum install -y aws-cfn-bootstrap telnet jq git sudo su ## Install kubectl curl -LO "https://storage.googleapis.com/kubernetes-release/release/v1.23.13/bin/linux/amd64/kubectl" install -o root -g root -m 0755 kubectl /usr/sbin/kubectl kubectl version --client ## Install eksctl curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp mv /tmp/eksctl /usr/sbin eksctl version ## Install HELM v3.8 curl -LO "https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz" tar -xvf helm-v3.8.2-linux-amd64.tar.gz chmod 755 linux-amd64/helm cp linux-amd64/helm /usr/sbin helm version ## Scripts mkdir /temp aws s3 sync s3://ee-assets-prod-us-west-2/modules/2343f58921ff4b66b136904c1265d64b/v1/prescript /temp chmod 755 /temp/prescript.sh cd /temp ./prescript.sh rm prescript.sh ## Cloud9 Environment Setup EKSCloud9Environment: Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: !Ref Cloud9EnvironmentName AutomaticStopTimeMinutes: 900 #15 hours OwnerArn: !If - Cloud9OwnerArnNotProvided - !Sub "arn:aws:sts::${AWS::AccountId}:assumed-role/TeamRole/MasterKey" #- !Sub "arn:aws:sts::${AWS::AccountId}:assumed-role/admin/haofeif-Isengard" - !Ref Cloud9OwnerArn Description: Use this to work with EKS FSx Labs InstanceType: !Ref ClientInstanceType SubnetId: !Ref PublicSubnet2 ImageId: resolve:ssm:/aws/service/cloud9/amis/amazonlinux-2-x86_64 Tags: - Key: Cloud9Instance Value: Active EKSCloud9BootstrappingTasks: Type: AWS::SSM::Document DependsOn: EKSCloud9Environment Properties: DocumentType: Command Content: schemaVersion: "2.2" description: Bootstrapping Cloud9 Environment parameters: Cloud9EnvironmentID: type: String description: Cloud9 Environment ID RegionName: type: String description: Region Name to run the command SharedUserARN01: type: String description: Shared User IAM ARN 01 for Cloud9 Environment to read-write SharedUserARN02: type: String description: Shared User IAM ARN 02 for Cloud9 Environment to read-write mainSteps: - action: aws:runShellScript name: bootstrapCloud9 inputs: runCommand: #!/bin/bash - sudo su - yum install -y aws-cfn-bootstrap telnet jq git ## Install kubectl - curl -LO "https://storage.googleapis.com/kubernetes-release/release/v1.23.13/bin/linux/amd64/kubectl" - install -o root -g root -m 0755 kubectl /usr/sbin/kubectl - kubectl version --client ## Install eksctl - curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp - mv /tmp/eksctl /usr/sbin - eksctl version ## Install HELM v3.8 - curl -LO "https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz" - tar -xvf helm-v3.8.2-linux-amd64.tar.gz - chmod 755 linux-amd64/helm - cp linux-amd64/helm /usr/sbin - helm version ## Cloning the Repo - sudo mkdir -p /home/ec2-user/environment/eks-fsx-workshop - sudo chmod -R 777 /home/ec2-user/environment/eks-fsx-workshop - git clone https://github.com/aws-samples/eks-fsx-workshop /home/ec2-user/environment/eks-fsx-workshop - sudo chown -R ec2-user:ec2-user /home/ec2-user/environment/eks-fsx-workshop # aws environment to share to different users - echo "Sharing the Cloud9 {{ Cloud9EnvironmentID }} to {{ SharedUserARN01 }}" - aws cloud9 create-environment-membership --environment-id {{ Cloud9EnvironmentID }} --region {{ RegionName }} --user-arn {{ SharedUserARN01 }} --permissions read-write - echo "Sharing the Cloud9 {{ Cloud9EnvironmentID }} to {{ SharedUserARN02 }}" - aws cloud9 create-environment-membership --environment-id {{ Cloud9EnvironmentID }} --region {{ RegionName }} --user-arn {{ SharedUserARN02 }} --permissions read-write EKSCloud9BootstrappingAssociation: Type: AWS::SSM::Association DependsOn: EKSCloud9BootstrappingTasks Properties: Name: !Ref EKSCloud9BootstrappingTasks Parameters: Cloud9EnvironmentID: [!Ref EKSCloud9Environment ] RegionName: [!Sub "${AWS::Region}"] SharedUserARN01: [!Sub "arn:aws:iam::${AWS::AccountId}:user/EEOverlord"] SharedUserARN02: [!Sub "arn:aws:sts::${AWS::AccountId}:assumed-role/eks-fsx-workshop-admin/MasterKey"] Targets: - Key: tag:Cloud9Instance Values: - Active ## Linux Instance Creation EKSCreationTasks: Type: AWS::SSM::Document DependsOn: - LinuxInstance - EKSCloud9Environment Properties: DocumentType: Command Content: schemaVersion: "2.2" description: Create EKS Cluster and Attach IAM role to the Cloud9 Environment parameters: PublicSubnet01: type: String description: Public Subnet 01 of the VPC for the EKS Cluster Control Plane PublicSubnet02: type: String description: Public Subnet 02 of the VPC for the EKS Cluster Control Plane PrivateSubnet01: type: String description: Private Subnet 01 of the VPC for the EKS Cluster Control Plane PrivateSubnet02: type: String description: Private Subnet 02 of the VPC for the EKS Cluster Control Plane VPCIdentifier: type: String description: VPC ID Cloud9EnvironmentID: type: String description: Cloud9 Environment ID Cloud9InstanceProfileName: type: String description: Cloud9 EC2 Instance Profile Name RegionName: type: String description: Region Name to run the command mainSteps: - action: aws:runShellScript name: SetupCloud9Environments inputs: runCommand: - echo ">>> find instance using environment Id= {{ Cloud9EnvironmentID }}" - CLOUD9_INSTANCE_ID=$(aws ec2 describe-instances --filter Name=tag:aws:cloud9:environment,Values={{ Cloud9EnvironmentID }} --query Reservations[0].Instances[0].InstanceId --region {{ RegionName }} --output text) - echo ">>> cloud9 instance id= $CLOUD9_INSTANCE_ID" - echo ">>> assign profile {{ Cloud9InstanceProfileName }} to instance $CLOUD9_INSTANCE_ID" - associationID=$(aws ec2 describe-iam-instance-profile-associations --filters "Name=instance-id,Values=$CLOUD9_INSTANCE_ID" --query IamInstanceProfileAssociations[0].AssociationId --region {{ RegionName }} --output text) - | if [ "$associationID" = "None" ] then echo "1" aws ec2 associate-iam-instance-profile --instance-id $CLOUD9_INSTANCE_ID --iam-instance-profile Name={{ Cloud9InstanceProfileName }} --region {{ RegionName }} else echo "0" aws ec2 replace-iam-instance-profile-association --association-id $associationID --iam-instance-profile Name={{ Cloud9InstanceProfileName }} --region {{ RegionName }} fi - action: aws:runShellScript name: createEKSCluster inputs: runCommand: - export currentregion=`curl http://169.254.169.254/latest/meta-data/placement/region` - echo "Current Region is:$currentregion" - if [ `aws eks list-clusters --region $currentregion |grep FSxONTAP-eks | wc -l` == 0 ]; - then - echo "EKS Cluster:FSxONTAP-eks is yet to be created, now creating the EKS cluster" - sudo mkdir -p /eks-fsx-workshop - sudo chmod -R 777 /eks-fsx-workshop - git clone https://github.com/aws-samples/eks-fsx-workshop /eks-fsx-workshop - sudo chown -R ec2-user:ec2-user /eks-fsx-workshop - sudo chmod -R 777 /eks-fsx-workshop - cd /eks-fsx-workshop/eks/FSxN - sed -i "s/ap-southeast-2/$currentregion/g" cluster.yaml - sed -i "s/vpc-id/{{ VPCIdentifier }}/g" cluster.yaml - sed -i "s/public-subnet-1/{{ PublicSubnet01 }}/g" cluster.yaml - sed -i "s/public-subnet-2/{{ PublicSubnet02 }}/g" cluster.yaml - sed -i "s/private-subnet1/{{ PrivateSubnet01 }}/g" cluster.yaml - sed -i "s/private-subnet2/{{ PrivateSubnet02 }}/g" cluster.yaml - echo "Printing the Cluster File" - cat cluster.yaml - eksctl create cluster -f ./cluster.yaml - fi - action: aws:runShellScript name: createS3bucketsforFSxLustre inputs: runCommand: - if [ `aws s3 ls |awk '{print $3}'|grep ^fsxl | wc -l` == 0 ]; - then - aws eks update-kubeconfig --name FSxONTAP-eks --region {{ RegionName }} - random=`echo $RANDOM | md5sum | head -c 12; echo` - cd /eks-fsx-workshop/FSxCFN - s3_bucket_name="fsxl-${random}" - s3_2nd_bucket_name="fsxl-2ndregion-${random}" - echo "Creating S3 bucket ${s3_bucket_name}" - aws cloudformation create-stack --stack-name ${s3_bucket_name} --region {{ RegionName }} --template-body file://./S3Buckets.yaml --parameters ParameterKey=S3BucketName,ParameterValue=${s3_bucket_name} --capabilities CAPABILITY_NAMED_IAM - echo "Creating S3 bucket ${s3_2nd_bucket_name}" - aws cloudformation create-stack --stack-name ${s3_2nd_bucket_name} --region us-east-2 --template-body file://./S3Buckets.yaml --parameters ParameterKey=S3BucketName,ParameterValue=${s3_2nd_bucket_name} --capabilities CAPABILITY_NAMED_IAM - echo "Creating IAM Role and Policy for S3 Cross Region Replication" - iam_role_name="s3-crr-${random}" - sed -i "s/DOC-EXAMPLE-BUCKET1/$s3_bucket_name/g" S3ReplicationIAM.yaml - sed -i "s/DOC-EXAMPLE-BUCKET2/$s3_2nd_bucket_name/g" S3ReplicationIAM.yaml - aws cloudformation create-stack --stack-name ${iam_role_name} --region {{ RegionName }} --template-body file://./S3ReplicationIAM.yaml --parameters ParameterKey=IAMRoleName,ParameterValue=${iam_role_name} --capabilities CAPABILITY_NAMED_IAM - echo "Creating Security Group for FSx for Lustre" #- SECURITY_GROUP_SOURCE_ID=$(aws eks describe-cluster --name FSxONTAP-eks --region {{ RegionName }} --query "cluster.resourcesVpcConfig.securityGroupIds" --output text) - cp fsxL-SecurityGroup.yaml fsxL-SecurityGroup.yaml.bak - sed -i "s/myVpc/{{ VPCIdentifier }}/g" fsxL-SecurityGroup.yaml #- sed -i "s/FSxLSecurityGroupID/$SECURITY_GROUP_SOURCE_ID/g" fsxL-SecurityGroup.yaml - aws cloudformation create-stack --stack-name FSxL-SecurityGroup-01 --region {{ RegionName }} --template-body file://./fsxL-SecurityGroup.yaml --parameters ParameterKey=SecurityGroupName,ParameterValue=FSxLSecurityGroup01 --capabilities CAPABILITY_NAMED_IAM - rm -f fsxL-SecurityGroup.yaml - mv fsxL-SecurityGroup.yaml.bak fsxL-SecurityGroup.yaml - fi - action: aws:runShellScript name: create2ndEKSClusterinanotherRegion inputs: runCommand: - if [ `aws eks list-clusters --region us-east-2 |grep FSxlustre-eks02 | wc -l` == 0 ]; - then - echo "EKS Cluster:FSxlustre-eks02 is yet to be created, now creating the EKS cluster in us-east-2" - eksctl create cluster --name FSxlustre-eks02 --region us-east-2 --nodes=2 --instance-types=c4.2xlarge - aws eks update-kubeconfig --name FSxlustre-eks02 --region us-east-2 - ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text) - CLUSTER_NAME="FSxlustre-eks02" - echo "Associating the OIDC Provider to EKS cluster $CLUSTER_NAME" - oidc_id=$(aws eks describe-cluster --name $CLUSTER_NAME --region us-east-2 --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5) - eksctl utils associate-iam-oidc-provider --cluster $CLUSTER_NAME --region us-east-2 --approve - VPC_ID=$(aws eks describe-cluster --name $CLUSTER_NAME --region us-east-2 --query "cluster.resourcesVpcConfig.vpcId" --output text) - SUBNET_ID=$(aws eks describe-cluster --name $CLUSTER_NAME --region us-east-2 --query "cluster.resourcesVpcConfig.subnetIds[0]" --output text) - echo "Creating Security Groups for FSx for Lustre in region us-east-2" #- SECURITY_GROUP_SOURCE_ID=$(aws eks describe-cluster --name $CLUSTER_NAME --region us-east-2 --query "cluster.resourcesVpcConfig.securityGroupIds" --output text) - cd /eks-fsx-workshop/FSxCFN - sed -i "s/myVpc/$VPC_ID/g" fsxL-SecurityGroup.yaml #- sed -i "s/FSxLSecurityGroupID/$SECURITY_GROUP_SOURCE_ID/g" fsxL-SecurityGroup.yaml - aws cloudformation create-stack --stack-name FSxL-SecurityGroup-02 --region us-east-2 --template-body file://./fsxL-SecurityGroup.yaml --parameters ParameterKey=SecurityGroupName,ParameterValue=FSxLSecurityGroup02 --capabilities CAPABILITY_NAMED_IAM - sleep 120 - SECURITY_GROUP_ID=$(aws cloudformation describe-stacks --stack-name FSxL-SecurityGroup-02 --region us-east-2 --query "Stacks[0].Outputs[0].OutputValue" --output text) - S3_BUCKET=$(aws s3 ls |grep fsxl-2nd | awk '{print$3}') - echo "Creating IAM Role for Service Account for FSx for Lustre 2nd Cluster" - aws iam create-policy --policy-name Amazon_2nd_FSx_Lustre_CSI_Driver --region us-east-2 --policy-document file://fsx-csi-driver.json - eksctl create iamserviceaccount --name fsx-csi-controller-sa --namespace kube-system --cluster $CLUSTER_NAME --region us-east-2 --attach-policy-arn arn:aws:iam::$ACCOUNT_ID:policy/Amazon_2nd_FSx_Lustre_CSI_Driver --approve - sleep 120 - fi - action: aws:runShellScript name: ConfigureFSxLCSI inputs: runCommand: - cd /eks-fsx-workshop/eks/FSxL - ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text) - CLUSTER_NAME="FSxlustre-eks02" - SECURITY_GROUP_ID=$(aws cloudformation describe-stacks --stack-name FSxL-SecurityGroup-02 --region us-east-2 --query "Stacks[0].Outputs[0].OutputValue" --output text) - S3_BUCKET=$(aws s3 ls |grep fsxl-2nd | awk '{print$3}') - SUBNET_ID=$(aws eks describe-cluster --name $CLUSTER_NAME --region us-east-2 --query "cluster.resourcesVpcConfig.subnetIds[0]" --output text) - ROLE_ARN=$(aws cloudformation describe-stacks --stack-name "eksctl-${CLUSTER_NAME}-addon-iamserviceaccount-kube-system-fsx-csi-controller-sa" --region us-east-2 --query "Stacks[0].Outputs[0].OutputValue" --output text) - echo "Firstly checking kubectl is working fine" - aws eks update-kubeconfig --name FSxlustre-eks02 --region us-east-2 - export KUBECONFIG="${KUBECONFIG}:/root/.kube/config" - echo $KUBECONFIG - echo $HOME - kubectl version - kubectl config get-contexts - kubectl get nodes - echo "Deploying CSI Driver for FSx Lustre" - kubectl apply -k "github.com/kubernetes-sigs/aws-fsx-csi-driver/deploy/kubernetes/overlays/stable/?ref=master" - kubectl annotate serviceaccount -n kube-system fsx-csi-controller-sa eks.amazonaws.com/role-arn=$ROLE_ARN --overwrite=true - echo "Deploying Storage Class" - sed -i "s/SUBNET_ID/$SUBNET_ID/g" fsxL-storage-class.yaml - sed -i "s/SECURITY_GROUP_ID/$SECURITY_GROUP_ID/g" fsxL-storage-class.yaml - sed -i "s/S3_BUCKET/$S3_BUCKET/g" fsxL-storage-class.yaml - kubectl apply -f fsxL-storage-class.yaml - sleep 10 - kubectl apply -f claim.yaml EKSCreationAssociation: Type: AWS::SSM::Association Properties: Name: !Ref EKSCreationTasks Parameters: VPCIdentifier: [!Ref VPC] PublicSubnet01: [!Ref PublicSubnet1] PublicSubnet02: [!Ref PublicSubnet2] PrivateSubnet01: [!Ref PrivateSubnet1] PrivateSubnet02: [!Ref PrivateSubnet2] Cloud9EnvironmentID: [!Ref EKSCloud9Environment ] Cloud9InstanceProfileName: [!Ref EC2InstanceProfile] RegionName: [!Sub "${AWS::Region}"] Targets: - Key: InstanceIds Values: [ !Ref LinuxInstance ] Outputs: VPCId: Description: "VPCId of VPC" Value: Ref: "VPC" Export: Name: !Sub "${AWS::Region}-${AWS::StackName}-VPC" PrivateSubnet1: Description: "SubnetId of private subnet 1" Value: Ref: "PrivateSubnet1" Export: Name: !Sub "${AWS::Region}-${AWS::StackName}-PrivateSubnet1" PrivateSubnet2: Description: "SubnetId of private subnet 2" Value: Ref: "PrivateSubnet2" Export: Name: !Sub "${AWS::Region}-${AWS::StackName}-PrivateSubnet2" PublicSubnet1: Description: "SubnetId of public subnet 1" Value: Ref: "PublicSubnet1" Export: Name: !Sub "${AWS::Region}-${AWS::StackName}-PublicSubnet1" PublicSubnet2: Description: "SubnetId of public subnet 2" Value: Ref: "PublicSubnet2" Export: Name: !Sub "${AWS::Region}-${AWS::StackName}-PublicSubnet2" PrivateRouteTable1: Description: "Route table of private subnet" Value: Ref: "PrivateRouteTable1" Export: Name: !Sub "${AWS::Region}-${AWS::StackName}-PrivateRouteTable1" ## FSxFilesystem Outputs FSxFileSystemID: Description: File System ID for FSx for NetAPP ONTAP Value: !Ref FSxONTAP SMFSxSecretManager: Description: Secret Manager ARN for FSx for NetAPP ONTAP Value: !Ref SMFsxAdminPassword SMSVMSecretManager: Description: Secret Manager ARN for FSx for NetAPP ONTAP Storage Virtual Machine (SVM) Value: !Ref SMSVMAdminPassword SecretsManagerIAMPolicyARN: Description: Trident IAM Policy ARN for Trident Backend Configuration IAM Role for Service Account Value: !Ref SecretsManagerIAMPolicy ### EC2 WindowsInstance: Description: Public IP address of the newly created EC2 instance Value: 'Fn::GetAtt': - WindowsInstance - PublicIp Secrets: Description: ARN of the Secrets Manager Value: !Ref AdminSecret LinuxInstance: Description: Public IP address of the newly created EC2 instance Value: 'Fn::GetAtt': - LinuxInstance - PublicIp ### Cloud9 EKSCloud9EnvId: Description: ID of the EKS Lab IDE Value: !Ref EKSCloud9Environment