tool/processors/ssm/ssm.go (126 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
package ssm
import (
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/aws/amazon-cloudwatch-agent/tool/data"
"github.com/aws/amazon-cloudwatch-agent/tool/processors"
"github.com/aws/amazon-cloudwatch-agent/tool/runtime"
"github.com/aws/amazon-cloudwatch-agent/tool/util"
)
const (
ErrCodeAccessDeniedException = "AccessDeniedException"
defaultRetryCount = 1 //total attempts are defaultRetryCount+1
)
var Processor processors.Processor = &processor{}
type processor struct{}
func (p *processor) Process(ctx *runtime.Context, config *data.Config) {
answer := util.Yes("Do you want to store the config in the SSM parameter store?")
if !answer {
return
}
serializedConfig := util.ReadConfigFromJsonFile()
parameterStoreName := determineParameterStoreName(ctx)
region := determineRegion(ctx)
var err error
for i := 0; i <= defaultRetryCount; i++ {
creds := determineCreds(ctx)
err = sendConfigToParameterStore(serializedConfig, parameterStoreName, region, creds)
if err == nil {
fmt.Printf("Successfully put config to parameter store %s.\n", parameterStoreName)
return
}
if awsErr, ok := err.(awserr.Error); ok {
switch awsErr.Code() {
case ErrCodeAccessDeniedException:
fmt.Printf("Please make sure the creds you used have the right permissions configured for SSM access.\n")
continue
default:
fmt.Printf("Error code: %s, message: %s, original error: %v\n", awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
}
}
break
}
fmt.Printf("Error in putting config to parameter store %s: %v\n", parameterStoreName, err)
}
func (p *processor) NextProcessor(ctx *runtime.Context, config *data.Config) interface{} {
return nil
}
func determineCreds(ctx *runtime.Context) *credentials.Credentials {
accessKeys := []string{}
sdkAccessKey, _, sdkCreds := util.SDKCredentials()
sdkAccessKeyDesc := ""
if sdkCreds != nil {
sdkAccessKeyDesc = sdkAccessKey + "(From SDK)"
accessKeys = append(accessKeys, sdkAccessKeyDesc)
}
fileAccessKey := ""
fileAccessKeyDesc := ""
fileCredentialsProvider := credentials.NewSharedCredentials("", "AmazonCloudWatchAgent")
fileCreds, err := fileCredentialsProvider.Get()
if err == nil {
fileAccessKey = fileCreds.AccessKeyID
fileAccessKeyDesc = fileAccessKey + "(From Profile: AmazonCloudWatchAgent)"
accessKeys = append(accessKeys, fileAccessKeyDesc)
}
if len(accessKeys) > 0 {
accessKeys = append(accessKeys, "Other")
answer := util.Choice("Which AWS credential should be used to send json config to parameter store?", 1, accessKeys)
if answer == sdkAccessKeyDesc {
return sdkCreds
} else if answer == fileAccessKeyDesc {
return fileCredentialsProvider
}
}
return askCreds()
}
func askCreds() *credentials.Credentials {
accessKey := util.Ask("Please provide credentials to upload the json config file to parameter store.\nAWS Access Key:")
secretKey := util.Ask("AWS Secret Key:")
creds := credentials.NewStaticCredentials(accessKey, secretKey, "")
return creds
}
func determineParameterStoreName(ctx *runtime.Context) string {
defaultParameterStoreName := "AmazonCloudWatch-" + ctx.OsParameter
parameterStoreName := util.AskWithDefault("What parameter store name do you want to use to store your config? (Use 'AmazonCloudWatch-' prefix if you use our managed AWS policy)", defaultParameterStoreName)
return parameterStoreName
}
func determineRegion(ctx *runtime.Context) string {
var region string
if !ctx.IsOnPrem {
region = util.DefaultEC2Region()
} else {
region = util.SDKRegionWithProfile("AmazonCloudWatchAgent")
}
if region == "" {
region = "us-east-1"
}
region = util.AskWithDefault("Which region do you want to store the config in the parameter store?", region)
return region
}
func sendConfigToParameterStore(config, parameterStoreName, region string, creds *credentials.Credentials) error {
awsConfig := aws.NewConfig().WithRegion(region)
if creds != nil {
awsConfig = awsConfig.WithCredentials(creds)
}
ses, err := session.NewSession(awsConfig)
if err != nil {
fmt.Printf("Error in creating session:\n %v\n", err)
return err
}
ssmClient := ssm.New(ses)
input := ssm.PutParameterInput{}
input.SetName(parameterStoreName)
input.SetOverwrite(true)
hostName, _ := os.Hostname()
input.SetDescription(fmt.Sprintf("Generated by wizard on %s at %s", hostName, time.Now().Format(time.RFC1123)))
input.SetType("String")
input.SetValue(config)
_, err = ssmClient.PutParameter(&input)
return err
}