From 56b4a512eda357fef1780b4ae1c8b4573c87b532 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 5 Feb 2021 14:54:16 +0100 Subject: [PATCH] remove aws datasources --- datasource/.gitkeep | 0 datasource/amazon/ami/data.go | 97 ---------- datasource/amazon/ami/data.hcl2spec.go | 101 ---------- datasource/amazon/ami/data_acc_test.go | 64 ------- datasource/amazon/ami/data_test.go | 45 ----- .../test-fixtures/configure-source-ssh.ps1 | 161 ---------------- datasource/amazon/secretsmanager/data.go | 168 ---------------- .../amazon/secretsmanager/data.hcl2spec.go | 99 ---------- .../amazon/secretsmanager/data_acc_test.go | 179 ------------------ datasource/amazon/secretsmanager/data_test.go | 39 ---- 10 files changed, 953 deletions(-) delete mode 100644 datasource/.gitkeep delete mode 100644 datasource/amazon/ami/data.go delete mode 100644 datasource/amazon/ami/data.hcl2spec.go delete mode 100644 datasource/amazon/ami/data_acc_test.go delete mode 100644 datasource/amazon/ami/data_test.go delete mode 100644 datasource/amazon/ami/test-fixtures/configure-source-ssh.ps1 delete mode 100644 datasource/amazon/secretsmanager/data.go delete mode 100644 datasource/amazon/secretsmanager/data.hcl2spec.go delete mode 100644 datasource/amazon/secretsmanager/data_acc_test.go delete mode 100644 datasource/amazon/secretsmanager/data_test.go diff --git a/datasource/.gitkeep b/datasource/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/datasource/amazon/ami/data.go b/datasource/amazon/ami/data.go deleted file mode 100644 index 11f7563b4..000000000 --- a/datasource/amazon/ami/data.go +++ /dev/null @@ -1,97 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type DatasourceOutput,Config -package ami - -import ( - "fmt" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/hcl2helper" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/template/config" - awscommon "github.com/hashicorp/packer/builder/amazon/common" - "github.com/zclconf/go-cty/cty" -) - -type Datasource struct { - config Config -} - -type Config struct { - awscommon.AccessConfig `mapstructure:",squash"` - awscommon.AmiFilterOptions `mapstructure:",squash"` -} - -func (d *Datasource) ConfigSpec() hcldec.ObjectSpec { - return d.config.FlatMapstructure().HCL2Spec() -} - -func (d *Datasource) Configure(raws ...interface{}) error { - err := config.Decode(&d.config, nil, raws...) - if err != nil { - return err - } - - var errs *packersdk.MultiError - errs = packersdk.MultiErrorAppend(errs, d.config.AccessConfig.Prepare()...) - - if d.config.Empty() { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The `filters` must be specified")) - } - if d.config.NoOwner() { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("For security reasons, you must declare an owner.")) - } - - if errs != nil && len(errs.Errors) > 0 { - return errs - } - return nil -} - -type DatasourceOutput struct { - // The ID of the AMI. - ID string `mapstructure:"id"` - // The name of the AMI. - Name string `mapstructure:"name"` - // The date of creation of the AMI. - CreationDate string `mapstructure:"creation_date"` - // The AWS account ID of the owner. - Owner string `mapstructure:"owner"` - // The owner alias. - OwnerName string `mapstructure:"owner_name"` - // The key/value combination of the tags assigned to the AMI. - Tags map[string]string `mapstructure:"tags"` -} - -func (d *Datasource) OutputSpec() hcldec.ObjectSpec { - return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec() -} - -func (d *Datasource) Execute() (cty.Value, error) { - session, err := d.config.Session() - if err != nil { - return cty.NullVal(cty.EmptyObject), err - } - - image, err := d.config.AmiFilterOptions.GetFilteredImage(&ec2.DescribeImagesInput{}, ec2.New(session)) - if err != nil { - return cty.NullVal(cty.EmptyObject), err - } - - imageTags := make(map[string]string, len(image.Tags)) - for _, tag := range image.Tags { - imageTags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) - } - - output := DatasourceOutput{ - ID: aws.StringValue(image.ImageId), - Name: aws.StringValue(image.Name), - CreationDate: aws.StringValue(image.CreationDate), - Owner: aws.StringValue(image.OwnerId), - OwnerName: aws.StringValue(image.ImageOwnerAlias), - Tags: imageTags, - } - return hcl2helper.HCL2ValueFromConfig(output, d.OutputSpec()), nil -} diff --git a/datasource/amazon/ami/data.hcl2spec.go b/datasource/amazon/ami/data.hcl2spec.go deleted file mode 100644 index 5560d2a66..000000000 --- a/datasource/amazon/ami/data.hcl2spec.go +++ /dev/null @@ -1,101 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type DatasourceOutput,Config"; DO NOT EDIT. - -package ami - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/amazon/common" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"` - AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"` - CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"` - CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"` - DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"` - InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` - MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"` - MFACode *string `mapstructure:"mfa_code" required:"false" cty:"mfa_code" hcl:"mfa_code"` - ProfileName *string `mapstructure:"profile" required:"false" cty:"profile" hcl:"profile"` - RawRegion *string `mapstructure:"region" required:"true" cty:"region" hcl:"region"` - SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"` - SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"` - SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"` - Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"` - VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"` - PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"` - Filters map[string]string `mapstructure:"filters" cty:"filters" hcl:"filters"` - Owners []string `mapstructure:"owners" cty:"owners" hcl:"owners"` - MostRecent *bool `mapstructure:"most_recent" cty:"most_recent" hcl:"most_recent"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false}, - "assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())}, - "custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false}, - "shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false}, - "decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false}, - "insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false}, - "max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false}, - "mfa_code": &hcldec.AttrSpec{Name: "mfa_code", Type: cty.String, Required: false}, - "profile": &hcldec.AttrSpec{Name: "profile", Type: cty.String, Required: false}, - "region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false}, - "secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false}, - "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, - "skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false}, - "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, - "vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())}, - "aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())}, - "filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false}, - "owners": &hcldec.AttrSpec{Name: "owners", Type: cty.List(cty.String), Required: false}, - "most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false}, - } - return s -} - -// FlatDatasourceOutput is an auto-generated flat version of DatasourceOutput. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatDatasourceOutput struct { - ID *string `mapstructure:"id" cty:"id" hcl:"id"` - Name *string `mapstructure:"name" cty:"name" hcl:"name"` - CreationDate *string `mapstructure:"creation_date" cty:"creation_date" hcl:"creation_date"` - Owner *string `mapstructure:"owner" cty:"owner" hcl:"owner"` - OwnerName *string `mapstructure:"owner_name" cty:"owner_name" hcl:"owner_name"` - Tags map[string]string `mapstructure:"tags" cty:"tags" hcl:"tags"` -} - -// FlatMapstructure returns a new FlatDatasourceOutput. -// FlatDatasourceOutput is an auto-generated flat version of DatasourceOutput. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*DatasourceOutput) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatDatasourceOutput) -} - -// HCL2Spec returns the hcl spec of a DatasourceOutput. -// This spec is used by HCL to read the fields of DatasourceOutput. -// The decoded values from this spec will then be applied to a FlatDatasourceOutput. -func (*FlatDatasourceOutput) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "id": &hcldec.AttrSpec{Name: "id", Type: cty.String, Required: false}, - "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, - "creation_date": &hcldec.AttrSpec{Name: "creation_date", Type: cty.String, Required: false}, - "owner": &hcldec.AttrSpec{Name: "owner", Type: cty.String, Required: false}, - "owner_name": &hcldec.AttrSpec{Name: "owner_name", Type: cty.String, Required: false}, - "tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false}, - } - return s -} diff --git a/datasource/amazon/ami/data_acc_test.go b/datasource/amazon/ami/data_acc_test.go deleted file mode 100644 index ced44bd3d..000000000 --- a/datasource/amazon/ami/data_acc_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package ami - -import ( - "fmt" - "os/exec" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/acctest" - amazonacc "github.com/hashicorp/packer/builder/amazon/ebs/acceptance" -) - -func TestAmazonAmi(t *testing.T) { - testCase := &acctest.DatasourceTestCase{ - Name: "amazon_ami_datasource_basic_test", - Teardown: func() error { - helper := amazonacc.AWSHelper{ - Region: "us-west-2", - AMIName: "packer-amazon-ami-test", - } - return helper.CleanUpAmi() - }, - Template: testDatasourceBasic, - Type: "amazon-ami", - Check: func(buildCommand *exec.Cmd, logfile string) error { - if buildCommand.ProcessState != nil { - if buildCommand.ProcessState.ExitCode() != 0 { - return fmt.Errorf("Bad exit code. Logfile: %s", logfile) - } - } - return nil - }, - } - acctest.TestDatasource(t, testCase) -} - -const testDatasourceBasic = ` -data "amazon-ami" "test" { - filters = { - virtualization-type = "hvm" - name = "Windows_Server-2016-English-Full-Base-*" - root-device-type = "ebs" - } - most_recent = true - owners = ["801119661308"] -} - -source "amazon-ebs" "basic-example" { - user_data_file = "./test-fixtures/configure-source-ssh.ps1" - region = "us-west-2" - source_ami = data.amazon-ami.test.id - instance_type = "t2.small" - ssh_agent_auth = false - ami_name = "packer-amazon-ami-test" - communicator = "ssh" - ssh_timeout = "10m" - ssh_username = "Administrator" -} - -build { - sources = [ - "source.amazon-ebs.basic-example" - ] -} -` diff --git a/datasource/amazon/ami/data_test.go b/datasource/amazon/ami/data_test.go deleted file mode 100644 index ff11431b2..000000000 --- a/datasource/amazon/ami/data_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package ami - -import ( - "testing" - - awscommon "github.com/hashicorp/packer/builder/amazon/common" -) - -func TestDatasourceConfigure_FilterBlank(t *testing.T) { - datasource := Datasource{ - config: Config{ - AmiFilterOptions: awscommon.AmiFilterOptions{}, - }, - } - if err := datasource.Configure(nil); err == nil { - t.Fatalf("Should error if filters map is empty or not specified") - } -} - -func TestRunConfigPrepare_SourceAmiFilterOwnersBlank(t *testing.T) { - datasource := Datasource{ - config: Config{ - AmiFilterOptions: awscommon.AmiFilterOptions{ - Filters: map[string]string{"foo": "bar"}, - }, - }, - } - if err := datasource.Configure(nil); err == nil { - t.Fatalf("Should error if Owners is not specified)") - } -} - -func TestRunConfigPrepare_SourceAmiFilterGood(t *testing.T) { - datasource := Datasource{ - config: Config{ - AmiFilterOptions: awscommon.AmiFilterOptions{ - Owners: []string{"1234567"}, - Filters: map[string]string{"foo": "bar"}, - }, - }, - } - if err := datasource.Configure(nil); err != nil { - t.Fatalf("err: %s", err) - } -} diff --git a/datasource/amazon/ami/test-fixtures/configure-source-ssh.ps1 b/datasource/amazon/ami/test-fixtures/configure-source-ssh.ps1 deleted file mode 100644 index 7c12dd742..000000000 --- a/datasource/amazon/ami/test-fixtures/configure-source-ssh.ps1 +++ /dev/null @@ -1,161 +0,0 @@ - -# Version and download URL -$openSSHVersion = "8.1.0.0p1-Beta" -$openSSHURL = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v$openSSHVersion/OpenSSH-Win64.zip" - -Set-ExecutionPolicy Unrestricted - -# GitHub became TLS 1.2 only on Feb 22, 2018 -[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; - -# Function to unzip an archive to a given destination -Add-Type -AssemblyName System.IO.Compression.FileSystem -Function Unzip -{ - [CmdletBinding()] - param( - [Parameter(Mandatory=$true, Position=0)] - [string] $ZipFile, - [Parameter(Mandatory=$true, Position=1)] - [string] $OutPath - ) - - [System.IO.Compression.ZipFile]::ExtractToDirectory($zipFile, $outPath) -} - -# Set various known paths -$openSSHZip = Join-Path $env:TEMP 'OpenSSH.zip' -$openSSHInstallDir = Join-Path $env:ProgramFiles 'OpenSSH' -$openSSHInstallScript = Join-Path $openSSHInstallDir 'install-sshd.ps1' -$openSSHDownloadKeyScript = Join-Path $openSSHInstallDir 'download-key-pair.ps1' -$openSSHDaemon = Join-Path $openSSHInstallDir 'sshd.exe' -$openSSHDaemonConfig = [io.path]::combine($env:ProgramData, 'ssh', 'sshd_config') - -# Download and unpack the binary distribution of OpenSSH -Invoke-WebRequest -Uri $openSSHURL ` - -OutFile $openSSHZip ` - -ErrorAction Stop - -Unzip -ZipFile $openSSHZip ` - -OutPath "$env:TEMP" ` - -ErrorAction Stop - -Remove-Item $openSSHZip ` - -ErrorAction SilentlyContinue - -# Move into Program Files -Move-Item -Path (Join-Path $env:TEMP 'OpenSSH-Win64') ` - -Destination $openSSHInstallDir ` - -ErrorAction Stop - -# Run the install script, terminate if it fails -& Powershell.exe -ExecutionPolicy Bypass -File $openSSHInstallScript -if ($LASTEXITCODE -ne 0) { - throw("Failed to install OpenSSH Server") -} - -# Add a firewall rule to allow inbound SSH connections to sshd.exe -New-NetFirewallRule -Name sshd ` - -DisplayName "OpenSSH Server (sshd)" ` - -Group "Remote Access" ` - -Description "Allow access via TCP port 22 to the OpenSSH Daemon" ` - -Enabled True ` - -Direction Inbound ` - -Protocol TCP ` - -LocalPort 22 ` - -Program "$openSSHDaemon" ` - -Action Allow ` - -ErrorAction Stop - -# Ensure sshd automatically starts on boot -Set-Service sshd -StartupType Automatic ` - -ErrorAction Stop - -# Set the default login shell for SSH connections to Powershell -New-Item -Path HKLM:\SOFTWARE\OpenSSH -Force -New-ItemProperty -Path HKLM:\SOFTWARE\OpenSSH ` - -Name DefaultShell ` - -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ` - -ErrorAction Stop - -$keyDownloadScript = @' -# Download the instance key pair and authorize Administrator logins using it -$openSSHAdminUser = 'c:\ProgramData\ssh' -$openSSHAuthorizedKeys = Join-Path $openSSHAdminUser 'authorized_keys' - -If (-Not (Test-Path $openSSHAdminUser)) { - New-Item -Path $openSSHAdminUser -Type Directory -} - -$keyUrl = "http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key" -$keyReq = [System.Net.WebRequest]::Create($keyUrl) -$keyResp = $keyReq.GetResponse() -$keyRespStream = $keyResp.GetResponseStream() - $streamReader = New-Object System.IO.StreamReader $keyRespStream -$keyMaterial = $streamReader.ReadToEnd() - -$keyMaterial | Out-File -Append -FilePath $openSSHAuthorizedKeys -Encoding ASCII - -# Ensure access control on authorized_keys meets the requirements -$acl = Get-ACL -Path $openSSHAuthorizedKeys -$acl.SetAccessRuleProtection($True, $True) -Set-Acl -Path $openSSHAuthorizedKeys -AclObject $acl - -$acl = Get-ACL -Path $openSSHAuthorizedKeys -$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( ` - "NT Authority\Authenticated Users", "ReadAndExecute", "Allow") -$acl.RemoveAccessRule($ar) -$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( ` - "BUILTIN\Administrators", "FullControl", "Allow") -$acl.RemoveAccessRule($ar) -$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( ` - "BUILTIN\Users", "FullControl", "Allow") -$acl.RemoveAccessRule($ar) -Set-Acl -Path $openSSHAuthorizedKeys -AclObject $acl - -Disable-ScheduledTask -TaskName "Download Key Pair" - -$sshdConfigContent = @" -# Modified sshd_config, created by Packer provisioner - -PasswordAuthentication yes -PubKeyAuthentication yes -PidFile __PROGRAMDATA__/ssh/logs/sshd.pid -AuthorizedKeysFile __PROGRAMDATA__/ssh/authorized_keys -AllowUsers Administrator - -Subsystem sftp sftp-server.exe -"@ - -Set-Content -Path C:\ProgramData\ssh\sshd_config ` - -Value $sshdConfigContent - -'@ -$keyDownloadScript | Out-File $openSSHDownloadKeyScript - -# Create Task - Ensure the name matches the verbatim version above -$taskName = "Download Key Pair" -$principal = New-ScheduledTaskPrincipal ` - -UserID "NT AUTHORITY\SYSTEM" ` - -LogonType ServiceAccount ` - -RunLevel Highest -$action = New-ScheduledTaskAction -Execute 'Powershell.exe' ` - -Argument "-NoProfile -File ""$openSSHDownloadKeyScript""" -$trigger = New-ScheduledTaskTrigger -AtStartup -Register-ScheduledTask -Action $action ` - -Trigger $trigger ` - -Principal $principal ` - -TaskName $taskName ` - -Description $taskName -Disable-ScheduledTask -TaskName $taskName - -# Run the install script, terminate if it fails -& Powershell.exe -ExecutionPolicy Bypass -File $openSSHDownloadKeyScript -if ($LASTEXITCODE -ne 0) { - throw("Failed to download key pair") -} - -# Restart to ensure public key authentication works and SSH comes up -Restart-Computer - -true \ No newline at end of file diff --git a/datasource/amazon/secretsmanager/data.go b/datasource/amazon/secretsmanager/data.go deleted file mode 100644 index e28ff4b8f..000000000 --- a/datasource/amazon/secretsmanager/data.go +++ /dev/null @@ -1,168 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type DatasourceOutput,Config -package secretsmanager - -import ( - "encoding/json" - "fmt" - "strconv" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/secretsmanager" - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/hcl2helper" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/template/config" - awscommon "github.com/hashicorp/packer/builder/amazon/common" - "github.com/hashicorp/packer/builder/amazon/common/awserrors" - "github.com/zclconf/go-cty/cty" -) - -type Datasource struct { - config Config -} - -type Config struct { - // Specifies the secret containing the version that you want to retrieve. - // You can specify either the Amazon Resource Name (ARN) or the friendly name of the secret. - Name string `mapstructure:"name" required:"true"` - // Optional key for JSON secrets that contain more than one value. When set, the `value` output will - // contain the value for the provided key. - Key string `mapstructure:"key"` - // Specifies the unique identifier of the version of the secret that you want to retrieve. - // Overrides version_stage. - VersionId string `mapstructure:"version_id"` - // Specifies the secret version that you want to retrieve by the staging label attached to the version. - // Defaults to AWSCURRENT. - VersionStage string `mapstructure:"version_stage"` - awscommon.AccessConfig `mapstructure:",squash"` -} - -func (d *Datasource) ConfigSpec() hcldec.ObjectSpec { - return d.config.FlatMapstructure().HCL2Spec() -} - -func (d *Datasource) Configure(raws ...interface{}) error { - err := config.Decode(&d.config, nil, raws...) - if err != nil { - return err - } - - var errs *packersdk.MultiError - errs = packersdk.MultiErrorAppend(errs, d.config.AccessConfig.Prepare()...) - - if d.config.Name == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("a 'name' must be provided")) - } - - if d.config.VersionStage == "" { - d.config.VersionStage = "AWSCURRENT" - } - - if errs != nil && len(errs.Errors) > 0 { - return errs - } - return nil -} - -type DatasourceOutput struct { - // When a [key](#key) is provided, this will be the value for that key. If a key is not provided, - // `value` will contain the first value found in the secret string. - Value string `mapstructure:"value"` - // The decrypted part of the protected secret information that - // was originally provided as a string. - SecretString string `mapstructure:"secret_string"` - // The decrypted part of the protected secret information that - // was originally provided as a binary. Base64 encoded. - SecretBinary string `mapstructure:"secret_binary"` - // The unique identifier of this version of the secret. - VersionId string `mapstructure:"version_id"` -} - -func (d *Datasource) OutputSpec() hcldec.ObjectSpec { - return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec() -} - -func (d *Datasource) Execute() (cty.Value, error) { - session, err := d.config.Session() - if err != nil { - return cty.NullVal(cty.EmptyObject), err - } - - input := &secretsmanager.GetSecretValueInput{ - SecretId: aws.String(d.config.Name), - } - - version := "" - if d.config.VersionId != "" { - input.VersionId = aws.String(d.config.VersionId) - version = d.config.VersionId - } else { - input.VersionStage = aws.String(d.config.VersionStage) - version = d.config.VersionStage - } - - secretsApi := secretsmanager.New(session) - secret, err := secretsApi.GetSecretValue(input) - if err != nil { - if awserrors.Matches(err, secretsmanager.ErrCodeResourceNotFoundException, "") { - return cty.NullVal(cty.EmptyObject), fmt.Errorf("Secrets Manager Secret %q Version %q not found", d.config.Name, version) - } - if awserrors.Matches(err, secretsmanager.ErrCodeInvalidRequestException, "You can’t perform this operation on the secret because it was deleted") { - return cty.NullVal(cty.EmptyObject), fmt.Errorf("Secrets Manager Secret %q Version %q not found", d.config.Name, version) - } - return cty.NullVal(cty.EmptyObject), fmt.Errorf("error reading Secrets Manager Secret Version: %s", err) - } - - value, err := getSecretValue(aws.StringValue(secret.SecretString), d.config.Key) - if err != nil { - return cty.NullVal(cty.EmptyObject), fmt.Errorf("error to get secret value: %q", err.Error()) - } - - versionId := aws.StringValue(secret.VersionId) - output := DatasourceOutput{ - Value: value, - SecretString: aws.StringValue(secret.SecretString), - SecretBinary: fmt.Sprintf("%s", secret.SecretBinary), - VersionId: versionId, - } - return hcl2helper.HCL2ValueFromConfig(output, d.OutputSpec()), nil -} - -func getSecretValue(secretString string, key string) (string, error) { - var secretValue map[string]interface{} - blob := []byte(secretString) - - //For those plaintext secrets just return the value - if json.Valid(blob) != true { - return secretString, nil - } - - err := json.Unmarshal(blob, &secretValue) - if err != nil { - return "", err - } - - if key == "" { - for _, v := range secretValue { - return getStringSecretValue(v) - } - } - - if v, ok := secretValue[key]; ok { - return getStringSecretValue(v) - } - - return "", nil -} - -func getStringSecretValue(v interface{}) (string, error) { - switch valueType := v.(type) { - case string: - return valueType, nil - case float64: - return strconv.FormatFloat(valueType, 'f', 0, 64), nil - default: - return "", fmt.Errorf("Unsupported secret value type: %T", valueType) - } -} diff --git a/datasource/amazon/secretsmanager/data.hcl2spec.go b/datasource/amazon/secretsmanager/data.hcl2spec.go deleted file mode 100644 index 6100a97bb..000000000 --- a/datasource/amazon/secretsmanager/data.hcl2spec.go +++ /dev/null @@ -1,99 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type DatasourceOutput,Config"; DO NOT EDIT. - -package secretsmanager - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/amazon/common" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - Name *string `mapstructure:"name" required:"true" cty:"name" hcl:"name"` - Key *string `mapstructure:"key" cty:"key" hcl:"key"` - VersionId *string `mapstructure:"version_id" cty:"version_id" hcl:"version_id"` - VersionStage *string `mapstructure:"version_stage" cty:"version_stage" hcl:"version_stage"` - AccessKey *string `mapstructure:"access_key" required:"true" cty:"access_key" hcl:"access_key"` - AssumeRole *common.FlatAssumeRoleConfig `mapstructure:"assume_role" required:"false" cty:"assume_role" hcl:"assume_role"` - CustomEndpointEc2 *string `mapstructure:"custom_endpoint_ec2" required:"false" cty:"custom_endpoint_ec2" hcl:"custom_endpoint_ec2"` - CredsFilename *string `mapstructure:"shared_credentials_file" required:"false" cty:"shared_credentials_file" hcl:"shared_credentials_file"` - DecodeAuthZMessages *bool `mapstructure:"decode_authorization_messages" required:"false" cty:"decode_authorization_messages" hcl:"decode_authorization_messages"` - InsecureSkipTLSVerify *bool `mapstructure:"insecure_skip_tls_verify" required:"false" cty:"insecure_skip_tls_verify" hcl:"insecure_skip_tls_verify"` - MaxRetries *int `mapstructure:"max_retries" required:"false" cty:"max_retries" hcl:"max_retries"` - MFACode *string `mapstructure:"mfa_code" required:"false" cty:"mfa_code" hcl:"mfa_code"` - ProfileName *string `mapstructure:"profile" required:"false" cty:"profile" hcl:"profile"` - RawRegion *string `mapstructure:"region" required:"true" cty:"region" hcl:"region"` - SecretKey *string `mapstructure:"secret_key" required:"true" cty:"secret_key" hcl:"secret_key"` - SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"` - SkipCredsValidation *bool `mapstructure:"skip_credential_validation" cty:"skip_credential_validation" hcl:"skip_credential_validation"` - Token *string `mapstructure:"token" required:"false" cty:"token" hcl:"token"` - VaultAWSEngine *common.FlatVaultAWSEngineOptions `mapstructure:"vault_aws_engine" required:"false" cty:"vault_aws_engine" hcl:"vault_aws_engine"` - PollingConfig *common.FlatAWSPollingConfig `mapstructure:"aws_polling" required:"false" cty:"aws_polling" hcl:"aws_polling"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, - "key": &hcldec.AttrSpec{Name: "key", Type: cty.String, Required: false}, - "version_id": &hcldec.AttrSpec{Name: "version_id", Type: cty.String, Required: false}, - "version_stage": &hcldec.AttrSpec{Name: "version_stage", Type: cty.String, Required: false}, - "access_key": &hcldec.AttrSpec{Name: "access_key", Type: cty.String, Required: false}, - "assume_role": &hcldec.BlockSpec{TypeName: "assume_role", Nested: hcldec.ObjectSpec((*common.FlatAssumeRoleConfig)(nil).HCL2Spec())}, - "custom_endpoint_ec2": &hcldec.AttrSpec{Name: "custom_endpoint_ec2", Type: cty.String, Required: false}, - "shared_credentials_file": &hcldec.AttrSpec{Name: "shared_credentials_file", Type: cty.String, Required: false}, - "decode_authorization_messages": &hcldec.AttrSpec{Name: "decode_authorization_messages", Type: cty.Bool, Required: false}, - "insecure_skip_tls_verify": &hcldec.AttrSpec{Name: "insecure_skip_tls_verify", Type: cty.Bool, Required: false}, - "max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false}, - "mfa_code": &hcldec.AttrSpec{Name: "mfa_code", Type: cty.String, Required: false}, - "profile": &hcldec.AttrSpec{Name: "profile", Type: cty.String, Required: false}, - "region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false}, - "secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false}, - "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, - "skip_credential_validation": &hcldec.AttrSpec{Name: "skip_credential_validation", Type: cty.Bool, Required: false}, - "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, - "vault_aws_engine": &hcldec.BlockSpec{TypeName: "vault_aws_engine", Nested: hcldec.ObjectSpec((*common.FlatVaultAWSEngineOptions)(nil).HCL2Spec())}, - "aws_polling": &hcldec.BlockSpec{TypeName: "aws_polling", Nested: hcldec.ObjectSpec((*common.FlatAWSPollingConfig)(nil).HCL2Spec())}, - } - return s -} - -// FlatDatasourceOutput is an auto-generated flat version of DatasourceOutput. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatDatasourceOutput struct { - Value *string `mapstructure:"value" cty:"value" hcl:"value"` - SecretString *string `mapstructure:"secret_string" cty:"secret_string" hcl:"secret_string"` - SecretBinary *string `mapstructure:"secret_binary" cty:"secret_binary" hcl:"secret_binary"` - VersionId *string `mapstructure:"version_id" cty:"version_id" hcl:"version_id"` -} - -// FlatMapstructure returns a new FlatDatasourceOutput. -// FlatDatasourceOutput is an auto-generated flat version of DatasourceOutput. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*DatasourceOutput) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatDatasourceOutput) -} - -// HCL2Spec returns the hcl spec of a DatasourceOutput. -// This spec is used by HCL to read the fields of DatasourceOutput. -// The decoded values from this spec will then be applied to a FlatDatasourceOutput. -func (*FlatDatasourceOutput) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "value": &hcldec.AttrSpec{Name: "value", Type: cty.String, Required: false}, - "secret_string": &hcldec.AttrSpec{Name: "secret_string", Type: cty.String, Required: false}, - "secret_binary": &hcldec.AttrSpec{Name: "secret_binary", Type: cty.String, Required: false}, - "version_id": &hcldec.AttrSpec{Name: "version_id", Type: cty.String, Required: false}, - } - return s -} diff --git a/datasource/amazon/secretsmanager/data_acc_test.go b/datasource/amazon/secretsmanager/data_acc_test.go deleted file mode 100644 index 2aeec663b..000000000 --- a/datasource/amazon/secretsmanager/data_acc_test.go +++ /dev/null @@ -1,179 +0,0 @@ -package secretsmanager - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "os/exec" - "regexp" - "testing" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/secretsmanager" - "github.com/hashicorp/packer-plugin-sdk/acctest" - "github.com/hashicorp/packer-plugin-sdk/retry" - awscommon "github.com/hashicorp/packer/builder/amazon/common" - "github.com/hashicorp/packer/builder/amazon/common/awserrors" -) - -func TestAmazonSecretsManager(t *testing.T) { - secret := &AmazonSecret{ - Name: "packer_datasource_secretsmanager_test_secret", - Key: "packer_test_key", - Value: "this_is_the_packer_test_secret_value", - Description: "this is a secret used in a packer acc test", - } - - testCase := &acctest.DatasourceTestCase{ - Name: "amazon_secretsmanager_datasource_basic_test", - Setup: func() error { - return secret.Create() - }, - Teardown: func() error { - return secret.Delete() - }, - Template: testDatasourceBasic, - Type: "amazon-secrestmanager", - Check: func(buildCommand *exec.Cmd, logfile string) error { - if buildCommand.ProcessState != nil { - if buildCommand.ProcessState.ExitCode() != 0 { - return fmt.Errorf("Bad exit code. Logfile: %s", logfile) - } - } - - logs, err := os.Open(logfile) - if err != nil { - return fmt.Errorf("Unable find %s", logfile) - } - defer logs.Close() - - logsBytes, err := ioutil.ReadAll(logs) - if err != nil { - return fmt.Errorf("Unable to read %s", logfile) - } - logsString := string(logsBytes) - - valueLog := fmt.Sprintf("null.basic-example: secret value: %s", secret.Value) - secretStringLog := fmt.Sprintf("null.basic-example: secret secret_string: %s", fmt.Sprintf("{%s:%s}", secret.Key, secret.Value)) - versionIdLog := fmt.Sprintf("null.basic-example: secret version_id: %s", aws.StringValue(secret.Info.VersionId)) - secretValueLog := fmt.Sprintf("null.basic-example: secret value: %s", secret.Value) - - if matched, _ := regexp.MatchString(valueLog+".*", logsString); !matched { - t.Fatalf("logs doesn't contain expected arn %q", logsString) - } - if matched, _ := regexp.MatchString(secretStringLog+".*", logsString); !matched { - t.Fatalf("logs doesn't contain expected secret_string %q", logsString) - } - if matched, _ := regexp.MatchString(versionIdLog+".*", logsString); !matched { - t.Fatalf("logs doesn't contain expected version_id %q", logsString) - } - if matched, _ := regexp.MatchString(secretValueLog+".*", logsString); !matched { - t.Fatalf("logs doesn't contain expected value %q", logsString) - } - return nil - }, - } - acctest.TestDatasource(t, testCase) -} - -const testDatasourceBasic = ` -data "amazon-secretsmanager" "test" { - name = "packer_datasource_secretsmanager_test_secret" - key = "packer_test_key" -} - -locals { - value = data.amazon-secretsmanager.test.value - secret_string = data.amazon-secretsmanager.test.secret_string - version_id = data.amazon-secretsmanager.test.version_id - secret_value = jsondecode(data.amazon-secretsmanager.test.secret_string)["packer_test_key"] -} - -source "null" "basic-example" { - communicator = "none" -} - -build { - sources = [ - "source.null.basic-example" - ] - - provisioner "shell-local" { - inline = [ - "echo secret value: ${local.value}", - "echo secret secret_string: ${local.secret_string}", - "echo secret version_id: ${local.version_id}", - "echo secret value: ${local.secret_value}" - ] - } -} -` - -type AmazonSecret struct { - Name string - Key string - Value string - Description string - - Info *secretsmanager.CreateSecretOutput - manager *secretsmanager.SecretsManager -} - -func (as *AmazonSecret) Create() error { - if as.manager == nil { - accessConfig := &awscommon.AccessConfig{} - session, err := accessConfig.Session() - if err != nil { - return fmt.Errorf("Unable to create aws session %s", err.Error()) - } - as.manager = secretsmanager.New(session) - } - - newSecret := &secretsmanager.CreateSecretInput{ - Description: aws.String(as.Description), - Name: aws.String(as.Name), - SecretString: aws.String(fmt.Sprintf(`{%q:%q}`, as.Key, as.Value)), - } - - secret := new(secretsmanager.CreateSecretOutput) - var err error - err = retry.Config{ - Tries: 11, - ShouldRetry: func(err error) bool { - if awserrors.Matches(err, "ResourceExistsException", "") { - _ = as.Delete() - return true - } - if awserrors.Matches(err, "InvalidRequestException", "already scheduled for deletion") { - return true - } - return false - }, - RetryDelay: (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 30 * time.Second, Multiplier: 2}).Linear, - }.Run(context.TODO(), func(_ context.Context) error { - secret, err = as.manager.CreateSecret(newSecret) - return err - }) - as.Info = secret - return err -} - -func (as *AmazonSecret) Delete() error { - if as.manager == nil { - accessConfig := &awscommon.AccessConfig{} - session, err := accessConfig.Session() - if err != nil { - return fmt.Errorf("Unable to create aws session %s", err.Error()) - } - as.manager = secretsmanager.New(session) - } - - secret := &secretsmanager.DeleteSecretInput{ - ForceDeleteWithoutRecovery: aws.Bool(true), - SecretId: aws.String(as.Name), - } - _, err := as.manager.DeleteSecret(secret) - return err -} diff --git a/datasource/amazon/secretsmanager/data_test.go b/datasource/amazon/secretsmanager/data_test.go deleted file mode 100644 index 5802b3b29..000000000 --- a/datasource/amazon/secretsmanager/data_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package secretsmanager - -import ( - "testing" -) - -func TestDatasourceConfigure_EmptySecretId(t *testing.T) { - datasource := Datasource{ - config: Config{}, - } - if err := datasource.Configure(nil); err == nil { - t.Fatalf("Should error if secret id is not specified") - } -} - -func TestDatasourceConfigure_Dafaults(t *testing.T) { - datasource := Datasource{ - config: Config{ - Name: "arn:1223", - }, - } - if err := datasource.Configure(nil); err != nil { - t.Fatalf("err: %s", err) - } - if datasource.config.VersionStage != "AWSCURRENT" { - t.Fatalf("VersionStage not set correctly") - } -} - -func TestDatasourceConfigure(t *testing.T) { - datasource := Datasource{ - config: Config{ - Name: "arn:1223", - }, - } - if err := datasource.Configure(nil); err != nil { - t.Fatalf("err: %s", err) - } -}