diff --git a/lib/web/integrations_awsoidc.go b/lib/web/integrations_awsoidc.go index 2dcdb01dcd4..ce20aaff25c 100644 --- a/lib/web/integrations_awsoidc.go +++ b/lib/web/integrations_awsoidc.go @@ -275,7 +275,7 @@ func (h *Handler) awsOIDCListDeployedDatabaseService(w http.ResponseWriter, r *h return nil, trace.BadParameter("an integration name is required") } - regions, err := fetchRelevantAWSRegions(ctx, clt, clt.DiscoveryConfigClient()) + regions, err := regionsForListingDeployedDatabaseService(ctx, r, clt, clt.DiscoveryConfigClient()) if err != nil { return nil, trace.Wrap(err) } @@ -290,6 +290,35 @@ func (h *Handler) awsOIDCListDeployedDatabaseService(w http.ResponseWriter, r *h }, nil } +func extractAWSRegionsFromQuery(r *http.Request) ([]string, error) { + var ret []string + for _, region := range r.URL.Query()["regions"] { + if err := aws.IsValidRegion(region); err != nil { + return nil, trace.BadParameter("invalid region %s", region) + } + ret = append(ret, region) + } + + return ret, nil +} + +func regionsForListingDeployedDatabaseService(ctx context.Context, r *http.Request, authClient databaseGetter, discoveryConfigsClient discoveryConfigLister) ([]string, error) { + if r.URL.Query().Has("regions") { + regions, err := extractAWSRegionsFromQuery(r) + if err != nil { + return nil, trace.Wrap(err) + } + return regions, err + } + + regions, err := fetchRelevantAWSRegions(ctx, authClient, discoveryConfigsClient) + if err != nil { + return nil, trace.Wrap(err) + } + + return regions, nil +} + type databaseGetter interface { GetResources(ctx context.Context, req *proto.ListResourcesRequest) (*proto.ListResourcesResponse, error) GetDatabases(context.Context) ([]types.Database, error) diff --git a/lib/web/integrations_awsoidc_test.go b/lib/web/integrations_awsoidc_test.go index c8c7f4a0cf7..62c3ca8ce69 100644 --- a/lib/web/integrations_awsoidc_test.go +++ b/lib/web/integrations_awsoidc_test.go @@ -22,6 +22,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "net/url" "strconv" "strings" @@ -1326,6 +1327,48 @@ func dummyDeployedDatabaseServices(count int, command []string) []*integrationv1 return ret } +func TestRegionsForListingDeployedDatabaseService(t *testing.T) { + ctx := context.Background() + + t.Run("regions query param is used instead of parsing internal resources", func(t *testing.T) { + clt := &mockRelevantAWSRegionsClient{ + databaseServices: &proto.ListResourcesResponse{ + Resources: []*proto.PaginatedResource{}, + }, + databases: make([]types.Database, 0), + discoveryConfigs: make([]*discoveryconfig.DiscoveryConfig, 0), + } + r := http.Request{ + URL: &url.URL{RawQuery: "regions=us-east-1®ions=us-east-2"}, + } + gotRegions, err := regionsForListingDeployedDatabaseService(ctx, &r, clt, clt) + require.NoError(t, err) + require.ElementsMatch(t, []string{"us-east-1", "us-east-2"}, gotRegions) + }) + + t.Run("fallbacks to internal resources when query param is not present", func(t *testing.T) { + clt := &mockRelevantAWSRegionsClient{ + databaseServices: &proto.ListResourcesResponse{ + Resources: []*proto.PaginatedResource{{Resource: &proto.PaginatedResource_DatabaseService{ + DatabaseService: &types.DatabaseServiceV1{Spec: types.DatabaseServiceSpecV1{ + ResourceMatchers: []*types.DatabaseResourceMatcher{ + {Labels: &types.Labels{"region": []string{"us-east-1"}}}, + {Labels: &types.Labels{"region": []string{"us-east-2"}}}, + }, + }}, + }}}, + }, + databases: make([]types.Database, 0), + discoveryConfigs: make([]*discoveryconfig.DiscoveryConfig, 0), + } + r := http.Request{ + URL: &url.URL{}, + } + gotRegions, err := regionsForListingDeployedDatabaseService(ctx, &r, clt, clt) + require.NoError(t, err) + require.ElementsMatch(t, []string{"us-east-1", "us-east-2"}, gotRegions) + }) +} func TestFetchRelevantAWSRegions(t *testing.T) { ctx := context.Background()