diff --git a/configuration.go b/configuration.go index ebe046b..3e49131 100644 --- a/configuration.go +++ b/configuration.go @@ -32,6 +32,7 @@ var ( maxRetriesConfig = &configuration{flag: "max-retries", envFlag: "max_retries", defaultValue: strconv.Itoa(awsClient.DefaultRetryerMaxNumRetries)} defaultDatabaseConfig = &configuration{flag: "default-database", envFlag: "default_database", defaultValue: ""} defaultTableConfig = &configuration{flag: "default-table", envFlag: "default_table", defaultValue: ""} + enableSigV4AuthConfig = &configuration{flag: "enable-sigv4-auth", envFlag: "enable_sigv4_auth", defaultValue: "true"} listenAddrConfig = &configuration{flag: "web.listen-address", envFlag: "", defaultValue: ":9201"} telemetryPathConfig = &configuration{flag: "web.telemetry-path", envFlag: "", defaultValue: "/metrics"} failOnLabelConfig = &configuration{flag: "fail-on-long-label", envFlag: "fail_on_long_label", defaultValue: "false"} diff --git a/main.go b/main.go index a18d9e3..a9b4116 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ import ( "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/go-kit/log" "github.com/gogo/protobuf/proto" "github.com/golang/snappy" @@ -83,6 +84,7 @@ type connectionConfig struct { defaultDatabase string defaultTable string enableLogging bool + enableSigV4Auth bool failOnLongMetricLabelName bool failOnInvalidSample bool listenAddr string @@ -145,9 +147,20 @@ func lambdaHandler(req events.APIGatewayProxyRequest) (events.APIGatewayProxyRes logger := cfg.createLogger() - awsCredentials, ok := parseBasicAuth(req.Headers[basicAuthHeader]) - if !ok { - return createErrorResponse(errors.NewParseBasicAuthHeaderError().(*errors.ParseBasicAuthHeaderError).Message()) + var awsCredentials *credentials.Credentials + var ok bool + + // If SigV4 authentication has been enabled, such as when write requests originate + // from the OpenTelemetry collector, credentials will be taken from the local environment. + // Otherwise, basic auth is used for AWS credentials + if cfg.enableSigV4Auth { + sess := session.Must(session.NewSession()) + awsCredentials = sess.Config.Credentials + } else { + awsCredentials, ok = parseBasicAuth(req.Headers[basicAuthHeader]) + if !ok { + return createErrorResponse(errors.NewParseBasicAuthHeaderError().(*errors.ParseBasicAuthHeaderError).Message()) + } } awsConfigs := cfg.buildAWSConfig() @@ -280,7 +293,7 @@ func (cfg *connectionConfig) createLogger() (logger log.Logger) { } // parseBoolFromStrings parses the boolean configuration options from the strings in connectionConfig. -func (cfg *connectionConfig) parseBoolFromStrings(enableLogging, failOnLongMetricLabelName, failOnInvalidSample string) error { +func (cfg *connectionConfig) parseBoolFromStrings(enableLogging, failOnLongMetricLabelName, failOnInvalidSample, enableSigV4Auth string) error { var err error cfg.enableLogging, err = strconv.ParseBool(enableLogging) @@ -304,6 +317,13 @@ func (cfg *connectionConfig) parseBoolFromStrings(enableLogging, failOnLongMetri return timestreamError } + cfg.enableSigV4Auth, err = strconv.ParseBool(enableSigV4Auth) + if err != nil { + timestreamError := errors.NewParseSampleOptionError(failOnInvalidSample) + fmt.Println(timestreamError.Error()) + return timestreamError + } + return nil } @@ -328,7 +348,7 @@ func parseEnvironmentVariables() (*connectionConfig, error) { cfg.defaultTable = getOrDefault(defaultTableConfig) var err error - err = cfg.parseBoolFromStrings(getOrDefault(enableLogConfig), getOrDefault(failOnLabelConfig), getOrDefault(failOnInvalidSampleConfig)) + err = cfg.parseBoolFromStrings(getOrDefault(enableLogConfig), getOrDefault(failOnLabelConfig), getOrDefault(failOnInvalidSampleConfig), getOrDefault(enableSigV4AuthConfig)) if err != nil { return nil, err } @@ -357,6 +377,7 @@ func parseFlags() *connectionConfig { } var enableLogging string + var enableSigV4Auth string var failOnLongMetricLabelName string var failOnInvalidSample string @@ -373,6 +394,7 @@ func parseFlags() *connectionConfig { Default(failOnInvalidSampleConfig.defaultValue).StringVar(&failOnInvalidSample) a.Flag(certificateConfig.flag, "TLS server certificate file.").Default(certificateConfig.defaultValue).StringVar(&cfg.certificate) a.Flag(keyConfig.flag, "TLS server private key file.").Default(keyConfig.defaultValue).StringVar(&cfg.key) + a.Flag(enableSigV4AuthConfig.flag, "Whether to enable SigV4 authentication with the API Gateway. Default to 'false'.").Default(enableSigV4AuthConfig.defaultValue).StringVar(&enableSigV4Auth) flag.AddFlags(a, &cfg.promlogConfig) @@ -381,7 +403,7 @@ func parseFlags() *connectionConfig { os.Exit(1) } - if err := cfg.parseBoolFromStrings(enableLogging, failOnLongMetricLabelName, failOnInvalidSample); err != nil { + if err := cfg.parseBoolFromStrings(enableLogging, failOnLongMetricLabelName, failOnInvalidSample, enableSigV4Auth); err != nil { os.Exit(1) } diff --git a/main_test.go b/main_test.go index 7f62617..86f4c28 100644 --- a/main_test.go +++ b/main_test.go @@ -175,6 +175,7 @@ func setUp() ([]string, *connectionConfig) { defaultDatabase: "foo", defaultTable: "bar", enableLogging: true, + enableSigV4Auth: true, listenAddr: ":9201", maxRetries: 3, telemetryPath: "/metrics", @@ -365,6 +366,7 @@ func TestLambdaHandlerPrepareRequest(t *testing.T) { lambdaOptions: []lambdaEnvOptions{ {key: defaultTableConfig.envFlag, value: tableValue}, {key: defaultDatabaseConfig.envFlag, value: databaseValue}, + {key: enableSigV4AuthConfig.envFlag, value: "false"}, }, inputRequest: events.APIGatewayProxyRequest{ IsBase64Encoded: true, @@ -379,6 +381,7 @@ func TestLambdaHandlerPrepareRequest(t *testing.T) { lambdaOptions: []lambdaEnvOptions{ {key: defaultTableConfig.envFlag, value: tableValue}, {key: defaultDatabaseConfig.envFlag, value: databaseValue}, + {key: enableSigV4AuthConfig.envFlag, value: "false"}, }, inputRequest: events.APIGatewayProxyRequest{ IsBase64Encoded: true, @@ -658,6 +661,7 @@ func TestParseEnvironmentVariables(t *testing.T) { clientConfig: &clientConfig{region: "us-east-1"}, promlogConfig: defaultLogConfig, enableLogging: true, + enableSigV4Auth: true, failOnInvalidSample: false, failOnLongMetricLabelName: false, maxRetries: 3, diff --git a/serverless/DEVELOPER_README.md b/serverless/DEVELOPER_README.md index f9fae3e..b12943e 100644 --- a/serverless/DEVELOPER_README.md +++ b/serverless/DEVELOPER_README.md @@ -61,15 +61,21 @@ The `DefaultDatabase`, `DefaultTable` and `LogLevel` may be altered to fit your To install the Timestream Prometheus Connector service launch the AWS CloudFormation stack on the AWS CloudFormation console by choosing one of the "Launch Stack" buttons in the following table: -| Region | View | View in Composer | Launch | -|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| US East (N. Virginia) us-east-1 | [View](https://timestreamassets-us-east-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=us-east-1&templateURL=https://timestreamassets-us-east-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-east-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | -| US East (Ohio) us-east-2 | [View](https://timestreamassets-us-east-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=us-east-2&templateURL=https://timestreamassets-us-east-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch](https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/new?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-east-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | -| US West (Oregon) us-west-2 | [View](https://timestreamassets-us-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=us-west-2&templateURL=https://timestreamassets-us-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | -| Asia Pacific (Sydney) ap-southeast-2 | [View](https://timestreamassets-ap-southeast-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=ap-southeast-2&templateURL=https://timestreamassets-ap-southeast-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-2#/stacks/new?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-southeast-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | -| Asia Pacific (Tokyo) ap-northeast-1 | [View](https://timestreamassets-ap-northeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=ap-northeast-1&templateURL=https://timestreamassets-ap-northeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch](https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks/new?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-northeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | -| Europe (Frankfurt) eu-central-1 | [View](https://timestreamassets-eu-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=eu-central-1&templateURL=https://timestreamassets-eu-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch](https://console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/new?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | -| Europe (Ireland) eu-west-1 | [View](https://timestreamassets-eu-west-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=eu-west-1&templateURL=https://timestreamassets-eu-west-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch](https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/new?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-west-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Region | View | View in Composer | Launch Without SigV4 | Launch With SigV4 | +|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| +| US East (N. Virginia) us-east-1 | [View](https://timestreamassets-us-east-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=us-east-1&templateURL=https://timestreamassets-us-east-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-east-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-east-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| US East (Ohio) us-east-2 | [View](https://timestreamassets-us-east-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=us-east-2&templateURL=https://timestreamassets-us-east-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-east-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-east-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| US West (Oregon) us-west-2 | [View](https://timestreamassets-us-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=us-west-2&templateURL=https://timestreamassets-us-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-us-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Asia Pacific (Mumbai) ap-south-1 | [View](https://timestreamassets-ap-south-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=ap-south-1&templateURL=https://timestreamassets-ap-south-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-south-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-south-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-south-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-south-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Asia Pacific (Singapore) ap-southeast-1 | [View](https://timestreamassets-ap-southeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=ap-southeast-1&templateURL=https://timestreamassets-ap-southeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-southeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-southeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Asia Pacific (Sydney) ap-southeast-2 | [View](https://timestreamassets-ap-southeast-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=ap-southeast-2&templateURL=https://timestreamassets-ap-southeast-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-southeast-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-southeast-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Asia Pacific (Tokyo) ap-northeast-1 | [View](https://timestreamassets-ap-northeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=ap-northeast-1&templateURL=https://timestreamassets-ap-northeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-northeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ap-northeast-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Canada (Central) ca-central-1 | [View](https://timestreamassets-ca-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=ca-central-1&templateURL=https://timestreamassets-ca-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=ca-central-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ca-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=ca-central-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-ca-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Europe (Frankfurt) eu-central-1 | [View](https://timestreamassets-eu-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=eu-central-1&templateURL=https://timestreamassets-eu-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-central-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Europe (Ireland) eu-west-1 | [View](https://timestreamassets-eu-west-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=eu-west-1&templateURL=https://timestreamassets-eu-west-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-west-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-west-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Europe (London) eu-west-2 | [View](https://timestreamassets-eu-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=eu-west-2&templateURL=https://timestreamassets-eu-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-west-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-west-2#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-west-2.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Europe (Paris) eu-west-3 | [View](https://timestreamassets-eu-west-3.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=eu-west-3&templateURL=https://timestreamassets-eu-west-3.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-west-3#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-west-3.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-west-3#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-west-3.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | +| Europe (Stockholm) eu-north-1 | [View](https://timestreamassets-eu-north-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [View in Composer](https://console.aws.amazon.com/composer/canvas?region=eu-north-1&templateURL=https://timestreamassets-eu-north-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | [Launch Without SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-north-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-north-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml¶m_EnableSigV4Auth=false) | [Launch With SigV4](https://console.aws.amazon.com/cloudformation/home?region=eu-north-1#/stacks/create/review?stackName=PrometheusTimestreamConnector&templateURL=https://timestreamassets-eu-north-1.s3.amazonaws.com/timestream-prometheus-connector/template.yml) | > **Note**: Attempting to use one of the above "Launch" links to create an already existing stack will fail. To update an existing stack, such as the default `PrometheusTimestreamConnector` stack, via the AWS Console, go to the stacks page at `https://.console.aws.amazon.com/cloudformation/home`, select the stack you want to update from the list, then click "Update" to proceed through the update process. @@ -216,6 +222,7 @@ Follow the verification steps in [README.md#verification](../README.md#verificat | LambdaTimeoutInSeconds | The amount of time in seconds to run the connector on AWS Lambda before timing out. | 30 | | ReadThrottlingBurstLimit | The number of burst read requests per second that API Gateway permits. | 1200 | | WriteThrottlingBurstLimit | The number of burst write requests per second that API Gateway permits. | 1200 | +| EnableSigV4Auth | Whether to enable SigV4 authentication for the API Gateway. | true | ### IAM Permissions Configuration Options diff --git a/serverless/template.yml b/serverless/template.yml index 3ac2570..4eccbb5 100644 --- a/serverless/template.yml +++ b/serverless/template.yml @@ -27,6 +27,13 @@ Parameters: MinValue: 2 Default: 30000 Description: "The maximum amount of time in milliseconds an API Gateway event will wait before timing out." + EnableSigV4Auth: + Type: "String" + AllowedValues: + - "true" + - "false" + Default: "true" + Description: "Whether to enable SigV4 authentication with the API Gateway. Defaults to false." LambdaTimeoutInSeconds: Type: Number MinValue: 3 @@ -57,6 +64,9 @@ Parameters: Default: "info" Description: "The output level for logs. Valid values include info, warn, debug, error" +Conditions: + SigV4AuthEnabled: !Equals [!Ref EnableSigV4Auth, "true"] + Resources: IAMLambdaRole: Type: "AWS::IAM::Role" @@ -82,60 +92,106 @@ Resources: - "logs:PutLogEvents" Resource: Fn::Sub: "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/PrometheusTimestreamConnector-LambdaFunction-*:*" + - Effect: "Allow" + Action: + - "timestream:DescribeEndpoints" + Resource: "*" + - Effect: "Allow" + Action: + - "timestream:WriteRecords" + - "timestream:Select" + Resource: !Sub "arn:aws:timestream:${AWS::Region}:${AWS::AccountId}:database/${DefaultDatabase}/table/${DefaultTable}" LambdaFunction: Type: "AWS::Serverless::Function" Properties: - Role: !GetAtt "IAMLambdaRole.Arn" + Role: !GetAtt IAMLambdaRole.Arn CodeUri: - Bucket: !Sub 'timestreamassets-${AWS::Region}' - Key: "timestream-prometheus-connector/timestream-prometheus-connector-linux-amd64-1.2.0.zip" + Bucket: !Sub 'timestreamassets-${AWS::Region}' + Key: "timestream-prometheus-connector/timestream-prometheus-connector-linux-amd64-1.2.0.zip" Description: "Prometheus remote storage connector for Amazon Timestream" Handler: "bootstrap" - MemorySize: !Ref "MemorySize" + MemorySize: !Ref MemorySize Timeout: !Ref LambdaTimeoutInSeconds Runtime: "provided.al2023" Environment: Variables: - default_database: !Ref "DefaultDatabase" - default_table: !Ref "DefaultTable" - region: !Ref "AWS::Region" - log_level: !Ref "LogLevel" - Events: - WriteApi: - Type: HttpApi - Properties: - ApiId: !Ref APIGateway - Method: POST - Path: /write - TimeoutInMillis: !Ref ApiGatewayTimeoutInMillis - RouteSettings: - ThrottlingBurstLimit: !Ref "WriteThrottlingBurstLimit" - - ReadApi: - Type: HttpApi - Properties: - ApiId: !Ref APIGateway - Method: POST - Path: /read - TimeoutInMillis: !Ref ApiGatewayTimeoutInMillis - RouteSettings: - ThrottlingBurstLimit: !Ref "ReadThrottlingBurstLimit" + default_database: !Ref DefaultDatabase + default_table: !Ref DefaultTable + region: !Ref AWS::Region + log_level: !Ref LogLevel + enable_sigv4_auth: !Ref EnableSigV4Auth APIGateway: - Type: "AWS::Serverless::HttpApi" + Type: AWS::ApiGatewayV2::Api + Properties: + Name: !Sub "${AWS::StackName}-APIGateway" + ProtocolType: HTTP + + APIGatewayIntegration: + Type: AWS::ApiGatewayV2::Integration + Properties: + ApiId: !Ref APIGateway + IntegrationType: AWS_PROXY + IntegrationUri: !GetAtt LambdaFunction.Arn + PayloadFormatVersion: "2.0" + TimeoutInMillis: !Ref ApiGatewayTimeoutInMillis + + WriteRoute: + Type: AWS::ApiGatewayV2::Route Properties: - StageName: !Ref "APIGatewayStageName" + ApiId: !Ref APIGateway + RouteKey: "POST /write" + Target: !Sub "integrations/${APIGatewayIntegration}" + AuthorizationType: !If [SigV4AuthEnabled, AWS_IAM, NONE] + + ReadRoute: + Type: AWS::ApiGatewayV2::Route + Properties: + ApiId: !Ref APIGateway + RouteKey: "POST /read" + Target: !Sub "integrations/${APIGatewayIntegration}" + AuthorizationType: !If [SigV4AuthEnabled, AWS_IAM, NONE] + + InvokeLambdaPermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref LambdaFunction + Action: lambda:InvokeFunction + Principal: apigateway.amazonaws.com + SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${APIGateway}/*" + + APIGatewayDeployment: + Type: AWS::ApiGatewayV2::Deployment + DependsOn: + - WriteRoute + - ReadRoute + Properties: + ApiId: !Ref APIGateway + + APIGatewayStage: + Type: AWS::ApiGatewayV2::Stage + DependsOn: + - APIGatewayDeployment + - WriteRoute + - ReadRoute + Properties: + StageName: !Ref APIGatewayStageName + ApiId: !Ref APIGateway + DeploymentId: !Ref APIGatewayDeployment + RouteSettings: + "POST /write": + ThrottlingBurstLimit: !Ref WriteThrottlingBurstLimit + "POST /read": + ThrottlingBurstLimit: !Ref ReadThrottlingBurstLimit Outputs: InvokeWriteURL: Description: Remote write URL for Prometheus - Value: - Fn::Sub: "https://${APIGateway}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${APIGatewayStageName}/write" + Value: !Sub "https://${APIGateway}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${APIGatewayStageName}/write" InvokeReadURL: Description: Remote read URL for Prometheus - Value: - Fn::Sub: "https://${APIGateway}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${APIGatewayStageName}/read" + Value: !Sub "https://${APIGateway}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${APIGatewayStageName}/read" DefaultDatabase: Description: The Prometheus default database name Value: