AWSTemplateFormatVersion: "2010-09-09" Description: This template instantiates an EC2 instance for configuration of the Qumulo Cluster and is then shutdown. Floating IPs, Sidecar role and permissions, SMB share, AD Config, EBS Volume Tagging, and CMK Policy management are all configured. Parameters: ProvisioningServerAMI: Type: String SecretsManagedPolicy: Type: String KeyName: Type: String Region: Type: String PrivateSubnetId: Type: String VPCCidr: Type: String Node1IP: Type: String FloatIPs: Type: String SMBShareName: Type: String ClusterPwd: Type: String VPCID: Type: String domainName: Type: String dcServerIp: Type: String SideCarSecretsArn: Type: String DomainControllerSecretsArn: Type: String CMK: Type: String StackName: Type: String BucketName: Type: String CMKPolicyPath: Type: String InstanceIDs: Type: String QStackName: Type: String Resources: ProvisionerSG: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'Enable ports for Provisioning Management of Qumulo' VpcId: !Ref VPCID SecurityGroupEgress: - CidrIp: 0.0.0.0/0 Description: Outbound traffic FromPort: 0 IpProtocol: '-1' ToPort: 0 SecurityGroupIngress: - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '22' IpProtocol: tcp ToPort: '22' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '9999' IpProtocol: tcp ToPort: '9999' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '4172' IpProtocol: tcp ToPort: '4172' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '21' IpProtocol: tcp ToPort: '21' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '80' IpProtocol: tcp ToPort: '80' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '111' IpProtocol: tcp ToPort: '111' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '443' IpProtocol: tcp ToPort: '443' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '445' IpProtocol: tcp ToPort: '445' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '2049' IpProtocol: tcp ToPort: '2049' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '3712' IpProtocol: tcp ToPort: '3712' - CidrIp: !Ref VPCCidr Description: 'TCP ports for NFS, SMB, FTP, Management, and Replication' FromPort: '8000' IpProtocol: tcp ToPort: '8000' - CidrIp: !Ref VPCCidr Description: UDP ports for NFS FromPort: '111' IpProtocol: udp ToPort: '111' - CidrIp: !Ref VPCCidr Description: UDP ports for NFS FromPort: '2049' IpProtocol: udp ToPort: '2049' ProvisionerRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' Path: / ManagedPolicyArns: - !Ref SecretsManagedPolicy Policies: - PolicyName: S3AccessPolcy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:GetObject" Resource: !Join - "" - - "arn:aws:s3:::" - !Ref BucketName - "/*" - PolicyName: KMSAccessPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "ec2:DeleteTags" - "ec2:CreateTags" - "ec2:DescribeVolumes" - "iam:GenerateCredentialReport" - "iam:List*" - "iam:Get*" - "iam:GenerateServiceLastAccessedDetails" - "iam:SimulatePrincipalPolicy" - "iam:SimulateCustomPolicy" - "kms:Decrypt" - "kms:PutKeyPolicy" - "kms:GetKeyPolicy" Resource: "*" ProvisionerProfile: Type: "AWS::IAM::InstanceProfile" Properties: Path: "/" Roles: - !Ref ProvisionerRole ProvisioningNode: Type: 'AWS::EC2::Instance' Properties: Tags: - Key: Name Value: !Join - "" - - !Ref "AWS::StackName" - " - Qumulo Provisioning Node" ImageId: !Ref ProvisioningServerAMI InstanceType: t3.large InstanceInitiatedShutdownBehavior: stop IamInstanceProfile: !Ref ProvisionerProfile KeyName: !Ref KeyName NetworkInterfaces: - AssociatePublicIpAddress: 'false' DeleteOnTermination: 'true' DeviceIndex: 0 GroupSet: - !Ref ProvisionerSG SubnetId: !Ref PrivateSubnetId UserData: Fn::Base64: !Sub | #!/bin/bash -xe exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1 echo "Running provisioning of qq node" yum install -y jq wget --no-check-certificate https://${Node1IP}/static/qq chmod 777 ./qq t_name=${StackName} echo $t_name > t_name.txt if [[ "$t_name" =~ "-StudioQStack-" ]]; then top_stackname=$(sed "s/-StudioQStack-.*//g" t_name.txt) else top_stackname=$t_name fi aws secretsmanager get-secret-value --secret-id ${SideCarSecretsArn} --region ${Region} --query "SecretString" --output text | jq -r .username > /root/username.txt read sc_username < /root/username.txt aws secretsmanager get-secret-value --secret-id ${SideCarSecretsArn} --region ${Region} --query "SecretString" --output text | jq -r .password > /root/password.txt read sc_password < /root/password.txt aws secretsmanager get-secret-value --secret-id ${DomainControllerSecretsArn} --region ${Region} --query "SecretString" --output text | jq -r .dcAdminUsername > /root/username.txt read ad_username < /root/username.txt aws secretsmanager get-secret-value --secret-id ${DomainControllerSecretsArn} --region ${Region} --query "SecretString" --output text | jq -r .dcAdminPassword > /root/password.txt read ad_password < /root/password.txt rm -f /root/password.txt rm -f /root/username.txt ./qq --host ${Node1IP} login -u admin -p "${ClusterPwd}" ./qq --host ${Node1IP} network_mod_network --network-id 1 --dns-servers ${dcServerIp} --dns-search-domains "${domainName}" until ./qq --host ${Node1IP} network_get_network --network-id 1 | grep -q "${domainName}"; do echo "Search domain for AD not yet added, retrying in 5 seconds." sleep 5 done echo "AD FQDN added to DNS search domains" ./qq --host ${Node1IP} ad_join -d ${domainName} -u "$ad_username" -p "$ad_password" until ./qq --host ${Node1IP} ad_list | grep -q "JOINED_TO_DOMAIN"; do echo "Not yet joined to AD domain, retrying in 5 seconds." sleep 5 done echo "Joined AD Domain" ./qq --host ${Node1IP} smb_add_share --name "${SMBShareName}" --fs-path "/${SMBShareName}" --create-fs-path --all-access --default-file-create-mode 777 --default-directory-create-mode 777 echo "SMB Share Added" ./qq --host ${Node1IP} auth_add_user --name $sc_username --primary-group Guests -p "$sc_password" ./qq --host ${Node1IP} auth_create_role --role $sc_username --description "Qumulo Sidecar User for AWS" ./qq --host ${Node1IP} auth_modify_role --role $sc_username -G PRIVILEGE_ANALYTICS_READ ./qq --host ${Node1IP} auth_modify_role --role $sc_username -G PRIVILEGE_CLUSTER_READ ./qq --host ${Node1IP} auth_modify_role --role $sc_username -G PRIVILEGE_FS_ATTRIBUTES_READ ./qq --host ${Node1IP} auth_modify_role --role $sc_username -G PRIVILEGE_NETWORK_READ ./qq --host ${Node1IP} auth_assign_role --role $sc_username --trustee $sc_username ./qq --host ${Node1IP} auth_assign_role --role "Observers" --trustee "${domainName}\Domain Users" ./qq --host ${Node1IP} network_mod_network --network-id 1 --floating-ip-ranges ${FloatIPs} ./qq --host ${Node1IP} time_set --set-use-ad sleep 10 IFS=', ' read -r -a ec2IDs <<< "${InstanceIDs}" for m in "${!!ec2IDs[@]}"; do gp2IDs+=($(aws ec2 describe-volumes --region ${Region} --filter "Name=attachment.instance-id, Values=${!ec2IDs[m]}" "Name=attachment.device, Values=/dev/x*" "Name=volume-type, Values=gp2" --query "Volumes[].VolumeId" --out "text")) gp3IDs+=($(aws ec2 describe-volumes --region ${Region} --filter "Name=attachment.instance-id, Values=${!ec2IDs[m]}" "Name=attachment.device, Values=/dev/x*" "Name=volume-type, Values=gp3" --query "Volumes[].VolumeId" --out "text")) st1IDs+=($(aws ec2 describe-volumes --region ${Region} --filter "Name=attachment.instance-id, Values=${!ec2IDs[m]}" "Name=attachment.device, Values=/dev/x*" "Name=volume-type, Values=st1" --query "Volumes[].VolumeId" --out "text")) sc1IDs+=($(aws ec2 describe-volumes --region ${Region} --filter "Name=attachment.instance-id, Values=${!ec2IDs[m]}" "Name=attachment.device, Values=/dev/x*" "Name=volume-type, Values=sc1" --query "Volumes[].VolumeId" --out "text")) done for m in "${!!gp2IDs[@]}"; do aws ec2 create-tags --region ${Region} --resources ${!gp2IDs[m]} --tags "Key=Name,Value=${QStackName}-gp2" done for m in "${!!gp3IDs[@]}"; do aws ec2 create-tags --region ${Region} --resources ${!gp3IDs[m]} --tags "Key=Name,Value=${QStackName}-gp3" done for m in "${!!st1IDs[@]}"; do aws ec2 create-tags --region ${Region} --resources ${!st1IDs[m]} --tags "Key=Name,Value=${QStackName}-st1" done for m in "${!!sc1IDs[@]}"; do aws ec2 create-tags --region ${Region} --resources ${!sc1IDs[m]} --tags "Key=Name,Value=${QStackName}-sc1" done if [ -z "${CMK}" ]; then echo "No CMK specified" else aws s3 cp s3://${CMKPolicyPath}cfn-init/cmk-policy-skeleton.json /root/add_policy.json aws iam list-roles | grep "IamForDiskRecoveryLambda" | grep "Arn" | grep $top_stackname | grep -o '"arn.*"' | tr -d '"' > /root/arn.txt cat /root/arn.txt | grep -o ".*/" | tr -d "/" > /root/role.txt cat /root/arn.txt | grep -o "/.*" | tr -d "/" > /root/lambda.txt sed "s/ROLE/$(cat /root/role.txt)/g" /root/add_policy.json > /root/add_policy2.json sed "s/LAMBDA/$(cat /root/lambda.txt)/g" /root/add_policy2.json > /root/add_policy3.json aws kms get-key-policy --region ${Region} --key-id ${CMK} --policy-name default --output text > /root/def_policy.json head -n -2 /root/def_policy.json > /root/new_policy.json cat /root/add_policy3.json >> /root/new_policy.json aws kms put-key-policy --region ${Region} --key-id ${CMK} --policy-name default --policy file:///root/new_policy.json fi echo "Sleeping 1 minute just to be sure" sleep 1m echo "Powering off Provisioning Node" poweroff Outputs: ProvisionerSGID: Value: !Ref ProvisionerSG