From b4d8d3b76ff93396bafeb4062bd514ada25ef137 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Wed, 24 Jan 2024 10:15:57 +0100 Subject: [PATCH] Implement 'aws_ssm' connection type #26 --- examples/aws_ssm/main.tf | 2 +- go.mod | 15 ++++++- go.sum | 32 +++++++++++++- internal/client/client.go | 2 +- internal/client/connection.go | 2 +- internal/client/connection_aws_ssm.go | 59 ++++++++++++------------- internal/client/connection_ssh.go | 2 +- internal/provider/instance/systemd.conf | 2 +- 8 files changed, 78 insertions(+), 38 deletions(-) diff --git a/examples/aws_ssm/main.tf b/examples/aws_ssm/main.tf index e846116..0c674dd 100644 --- a/examples/aws_ssm/main.tf +++ b/examples/aws_ssm/main.tf @@ -18,7 +18,7 @@ locals { env_type = "aem-single" host = "aem_single" - ssm_user = "ec2-user" + ssm_user = "root" tags = { Workspace = "aemc" diff --git a/go.mod b/go.mod index 884e4c5..c458e92 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,9 @@ module github.com/wttech/terraform-provider-aem go 1.19 require ( + github.com/aws/aws-sdk-go-v2 v1.24.1 + github.com/aws/aws-sdk-go-v2/config v1.26.6 + github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 github.com/hashicorp/terraform-plugin-docs v0.16.0 github.com/hashicorp/terraform-plugin-framework v1.4.2 github.com/hashicorp/terraform-plugin-go v0.19.0 @@ -21,7 +24,17 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect - github.com/aws/aws-sdk-go v1.48.12 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect + github.com/aws/smithy-go v1.19.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/fatih/color v1.16.0 // indirect diff --git a/go.sum b/go.sum index 7687308..4466e08 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,34 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkE github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.48.12 h1:n+eGzflzzvYubu2cOjqpVll7lF+Ci0ThyCpg5kzfzbo= -github.com/aws/aws-sdk-go v1.48.12/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= +github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= +github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= +github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE= +github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= +github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= +github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -95,6 +121,7 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= @@ -243,6 +270,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/client/client.go b/internal/client/client.go index b229425..2058954 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -206,7 +206,7 @@ func (c Client) FileCopy(localPath string, remotePath string, override bool) err return err } defer func() { _ = c.PathDelete(remoteTmpPath) }() - if err := c.connection.CopyFile(c.Sudo, localPath, remoteTmpPath); err != nil { + if err := c.connection.CopyFile(localPath, remoteTmpPath); err != nil { return err } if err := c.FileMove(remoteTmpPath, remotePath); err != nil { diff --git a/internal/client/connection.go b/internal/client/connection.go index 045496b..7b1f772 100644 --- a/internal/client/connection.go +++ b/internal/client/connection.go @@ -6,5 +6,5 @@ type Connection interface { Connect() error Disconnect() error Command(cmdLine []string) ([]byte, error) - CopyFile(sudo bool, localPath string, remotePath string) error + CopyFile(localPath string, remotePath string) error } diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index c34fb54..0fd0cff 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -1,20 +1,22 @@ package client import ( + "context" "encoding/base64" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/ssm" "os" "strings" + "time" ) type AWSSSMConnection struct { user string instanceId string region string - ssmClient *ssm.SSM + ssmClient *ssm.Client sessionId *string } @@ -25,22 +27,25 @@ func (a *AWSSSMConnection) Info() string { func (a *AWSSSMConnection) User() string { return a.user } + func (a *AWSSSMConnection) Connect() error { - // Create an AWS session - sess, err := session.NewSession(&aws.Config{ - Region: aws.String(a.region), - }) + // Specify the AWS region + cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(a.region)) + if err != nil { + return err + } + + // Create an SSM client + ssmClient := ssm.NewFromConfig(cfg) if err != nil { return fmt.Errorf("ssm: error creating AWS session: %v", err) } - // Connect to AWS instance using SSM - ssmClient := ssm.New(sess) startSessionInput := &ssm.StartSessionInput{ Target: aws.String(a.instanceId), } - startSessionOutput, err := ssmClient.StartSession(startSessionInput) + startSessionOutput, err := ssmClient.StartSession(context.Background(), startSessionInput) if err != nil { return fmt.Errorf("ssm: error starting session: %v", err) } @@ -57,7 +62,7 @@ func (a *AWSSSMConnection) Disconnect() error { SessionId: a.sessionId, } - _, err := a.ssmClient.TerminateSession(terminateSessionInput) + _, err := a.ssmClient.TerminateSession(context.Background(), terminateSessionInput) if err != nil { return fmt.Errorf("ssm: error terminating session: %v", err) } @@ -67,35 +72,34 @@ func (a *AWSSSMConnection) Disconnect() error { func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { // Execute command on the remote instance - command := aws.String(strings.Join(cmdLine, " ")) + command := strings.Join(cmdLine, " ") runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), - InstanceIds: []*string{aws.String(a.instanceId)}, - Parameters: map[string][]*string{ + InstanceIds: []string{a.instanceId}, + Parameters: map[string][]string{ "commands": {command}, }, } - runCommandOutput, err := a.ssmClient.SendCommand(runCommandInput) + runCommandOutput, err := a.ssmClient.SendCommand(context.Background(), runCommandInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } commandId := runCommandOutput.Command.CommandId - // Wait for command completion - err = a.ssmClient.WaitUntilCommandExecuted(&ssm.GetCommandInvocationInput{ + commandInvocationInput := &ssm.GetCommandInvocationInput{ CommandId: commandId, InstanceId: aws.String(a.instanceId), - }) + } + + waiter := ssm.NewCommandExecutedWaiter(a.ssmClient) + _, err = waiter.WaitForOutput(context.Background(), commandInvocationInput, time.Hour) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - getCommandOutput, err := a.ssmClient.GetCommandInvocation(&ssm.GetCommandInvocationInput{ - CommandId: commandId, - InstanceId: aws.String(a.instanceId), - }) + getCommandOutput, err := a.ssmClient.GetCommandInvocation(context.Background(), commandInvocationInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } @@ -103,7 +107,7 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { return []byte(*getCommandOutput.StandardOutputContent), nil } -func (a *AWSSSMConnection) CopyFile(sudo bool, localPath string, remotePath string) error { +func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { fileContent, err := os.ReadFile(localPath) if err != nil { return fmt.Errorf("ssm: error reading local file: %v", err) @@ -111,12 +115,7 @@ func (a *AWSSSMConnection) CopyFile(sudo bool, localPath string, remotePath stri encodedContent := base64.StdEncoding.EncodeToString(fileContent) cmd := fmt.Sprintf("echo -n %s | base64 -d > %s", encodedContent, remotePath) - var cmdLine []string - if sudo { - cmdLine = []string{"sudo", "sh", "-c", "\"" + cmd + "\""} - } else { - cmdLine = []string{"sh", "-c", "\"" + cmd + "\""} - } + cmdLine := []string{"sh", "-c", "\"" + cmd + "\""} _, err = a.Command(cmdLine) return err } diff --git a/internal/client/connection_ssh.go b/internal/client/connection_ssh.go index dc53947..c7baa18 100644 --- a/internal/client/connection_ssh.go +++ b/internal/client/connection_ssh.go @@ -112,7 +112,7 @@ func (s *SSHConnection) splitCommandLine(cmdLine []string) (string, []string) { return name, args } -func (s *SSHConnection) CopyFile(sudo bool, localPath string, remotePath string) error { +func (s *SSHConnection) CopyFile(localPath string, remotePath string) error { if err := s.client.Upload(localPath, remotePath); err != nil { return fmt.Errorf("ssh: cannot copy local file '%s' to remote path '%s' on host '%s': %w", localPath, remotePath, s.host, err) } diff --git a/internal/provider/instance/systemd.conf b/internal/provider/instance/systemd.conf index 9dca605..489215b 100644 --- a/internal/provider/instance/systemd.conf +++ b/internal/provider/instance/systemd.conf @@ -1,6 +1,6 @@ [Unit] Description=AEM Instances -Requires=network.target multi-user.target +Requires=network.target After=cloud-final.service [Service]