diff --git a/docs/sources/datasources/cloudwatch.md b/docs/sources/datasources/cloudwatch.md index 54195c139c8..ed9597e511f 100644 --- a/docs/sources/datasources/cloudwatch.md +++ b/docs/sources/datasources/cloudwatch.md @@ -105,6 +105,10 @@ Here is a minimal policy example: The `Assume Role ARN` field allows you to specify which IAM role to assume, if any. When left blank, the provided credentials are used directly and the associated role or user should have the required permissions. If this field is non-blank, on the other hand, the provided credentials are used to perform an [sts:AssumeRole](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) call. +### Endpoint + +The `Endpoint` field allows you to specify a custom endpoint URL that overrides the default generated endpoint for the CloudWatch API. Leave this field blank if you want to use the default generated endpoint. For more information on why and how to use Service endpoints, refer to the [AWS service endpoints documentation](https://docs.aws.amazon.com/general/latest/gr/rande.html). + ### EKS IAM roles for service accounts The Grafana process in the container runs as user 472 (called "grafana"). When Kubernetes mounts your projected credentials, they will by default only be available to the root user. In order to allow user 472 to access the credentials (and avoid it falling back to the IAM role attached to the EC2 instance), you will need to provide a [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for your pod. diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 430c05cfe42..88b3591f598 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -38,6 +38,7 @@ type datasourceInfo struct { AssumeRoleARN string ExternalID string Namespace string + Endpoint string AccessKey string SecretKey string @@ -96,7 +97,7 @@ func (e *cloudWatchExecutor) newSession(region string) (*session.Session, error) bldr := strings.Builder{} for i, s := range []string{ - dsInfo.AuthType.String(), dsInfo.AccessKey, dsInfo.Profile, dsInfo.AssumeRoleARN, region, + dsInfo.AuthType.String(), dsInfo.AccessKey, dsInfo.Profile, dsInfo.AssumeRoleARN, region, dsInfo.Endpoint, } { if i != 0 { bldr.WriteString(":") @@ -130,6 +131,10 @@ func (e *cloudWatchExecutor) newSession(region string) (*session.Session, error) cfgs = append(cfgs, regionCfg) } + if dsInfo.Endpoint != "" { + cfgs = append(cfgs, &aws.Config{Endpoint: aws.String(dsInfo.Endpoint)}) + } + switch dsInfo.AuthType { case authTypeSharedCreds: plog.Debug("Authenticating towards AWS with shared credentials", "profile", dsInfo.Profile, @@ -413,6 +418,7 @@ func (e *cloudWatchExecutor) getDSInfo(region string) *datasourceInfo { atStr := e.DataSource.JsonData.Get("authType").MustString() assumeRoleARN := e.DataSource.JsonData.Get("assumeRoleArn").MustString() externalID := e.DataSource.JsonData.Get("externalId").MustString() + endpoint := e.DataSource.JsonData.Get("endpoint").MustString() decrypted := e.DataSource.DecryptedValues() accessKey := decrypted["accessKey"] secretKey := decrypted["secretKey"] @@ -445,6 +451,7 @@ func (e *cloudWatchExecutor) getDSInfo(region string) *datasourceInfo { ExternalID: externalID, AccessKey: accessKey, SecretKey: secretKey, + Endpoint: endpoint, } } diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx index c4463932d31..3df8e6e6e17 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor.tsx @@ -315,6 +315,21 @@ export class ConfigEditor extends PureComponent { /> +
+
+ + Endpoint + +
+ +
+
+
); diff --git a/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap b/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap index 53fd134e641..47c9f1e9c1a 100644 --- a/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap +++ b/public/app/plugins/datasource/cloudwatch/components/__snapshots__/ConfigEditor.test.tsx.snap @@ -225,6 +225,30 @@ exports[`Render should disable access key id field 1`] = ` /> +
+
+ + Endpoint + +
+ +
+
+
`; @@ -454,6 +478,30 @@ exports[`Render should render component 1`] = ` /> +
+
+ + Endpoint + +
+ +
+
+
`; @@ -683,6 +731,30 @@ exports[`Render should show access key and secret access key fields 1`] = ` /> +
+
+ + Endpoint + +
+ +
+
+
`; @@ -912,6 +984,30 @@ exports[`Render should show arn role field 1`] = ` /> +
+
+ + Endpoint + +
+ +
+
+
`; @@ -1141,6 +1237,30 @@ exports[`Render should show credentials profile name field 1`] = ` /> +
+
+ + Endpoint + +
+ +
+
+
`; diff --git a/public/app/plugins/datasource/cloudwatch/types.ts b/public/app/plugins/datasource/cloudwatch/types.ts index d756dff63fa..0f3e3a7b2f9 100644 --- a/public/app/plugins/datasource/cloudwatch/types.ts +++ b/public/app/plugins/datasource/cloudwatch/types.ts @@ -62,6 +62,7 @@ export interface CloudWatchJsonData extends DataSourceJsonData { externalId?: string; database?: string; customMetricsNamespaces?: string; + endpoint?: string; } export interface CloudWatchSecureJsonData {