Skip to content

Commit

Permalink
Move all functionality for assume command into credentials/console
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexVulaj committed Oct 30, 2023
1 parent 3171aff commit f3ef69d
Show file tree
Hide file tree
Showing 17 changed files with 492 additions and 635 deletions.
188 changes: 0 additions & 188 deletions cmd/ocm-backplane/cloud/assume.go

This file was deleted.

2 changes: 0 additions & 2 deletions cmd/ocm-backplane/cloud/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ var CloudCmd = &cobra.Command{
func init() {
CloudCmd.AddCommand(CredentialsCmd)
CloudCmd.AddCommand(ConsoleCmd)
CloudCmd.AddCommand(TokenCmd)
CloudCmd.AddCommand(AssumeCmd)
}

func help(cmd *cobra.Command, _ []string) {
Expand Down
129 changes: 129 additions & 0 deletions cmd/ocm-backplane/cloud/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package cloud

import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/sts"
v1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
"github.com/openshift/backplane-cli/pkg/awsutil"
"github.com/openshift/backplane-cli/pkg/utils"
"io"
"net/http"
)

const OldFlowSupportRole = "role/RH-Technical-Support-Access"

var StsClientWithProxy = awsutil.StsClientWithProxy
var AssumeRoleWithJWT = awsutil.AssumeRoleWithJWT
var NewStaticCredentialsProvider = credentials.NewStaticCredentialsProvider
var AssumeRoleSequence = awsutil.AssumeRoleSequence

type assumeChainResponse struct {
AssumptionSequence []namedRoleArn `json:"assumptionSequence"`
}

type namedRoleArn struct {
Name string `json:"name"`
Arn string `json:"arn"`
}

func getIsolatedCredentials(clusterID string) (aws.Credentials, error) {
if clusterID == "" {
return aws.Credentials{}, errors.New("must provide non-empty cluster ID")
}

ocmToken, err := utils.DefaultOCMInterface.GetOCMAccessToken()
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to retrieve OCM token: %w", err)
}

email, err := utils.GetStringFieldFromJWT(*ocmToken, "email")
if err != nil {
return aws.Credentials{}, fmt.Errorf("unable to extract email from given token: %w", err)
}

bpConfig, err := GetBackplaneConfiguration()
if err != nil {
return aws.Credentials{}, fmt.Errorf("error retrieving backplane configuration: %w", err)
}

if bpConfig.AssumeInitialArn == "" {
return aws.Credentials{}, errors.New("backplane config is missing required `assume-initial-arn` property")
}

initialClient, err := StsClientWithProxy(bpConfig.ProxyURL)
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to create sts client: %w", err)
}

seedCredentials, err := AssumeRoleWithJWT(*ocmToken, bpConfig.AssumeInitialArn, initialClient)
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to assume role using JWT: %w", err)
}

backplaneClient, err := utils.DefaultClientUtils.MakeRawBackplaneAPIClientWithAccessToken(bpConfig.URL, *ocmToken)
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to create backplane client with access token: %w", err)
}

response, err := backplaneClient.GetAssumeRoleSequence(context.TODO(), clusterID)
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to fetch arn sequence: %w", err)
}
if response.StatusCode != http.StatusOK {
return aws.Credentials{}, fmt.Errorf("failed to fetch arn sequence: %v", response.Status)
}

bytes, err := io.ReadAll(response.Body)
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to read backplane API response body: %w", err)
}

roleChainResponse := &assumeChainResponse{}
err = json.Unmarshal(bytes, roleChainResponse)
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to unmarshal response: %w", err)
}

roleAssumeSequence := make([]string, 0, len(roleChainResponse.AssumptionSequence))
for _, namedRoleArn := range roleChainResponse.AssumptionSequence {
roleAssumeSequence = append(roleAssumeSequence, namedRoleArn.Arn)
}

seedClient := sts.NewFromConfig(aws.Config{
Region: "us-east-1",
Credentials: NewStaticCredentialsProvider(seedCredentials.AccessKeyID, seedCredentials.SecretAccessKey, seedCredentials.SessionToken),
})

targetCredentials, err := AssumeRoleSequence(email, seedClient, roleAssumeSequence, bpConfig.ProxyURL, awsutil.DefaultSTSClientProviderFunc)
if err != nil {
return aws.Credentials{}, fmt.Errorf("failed to assume role sequence: %w", err)
}
return targetCredentials, nil
}

func isIsolatedBackplaneAccess(cluster *v1.Cluster) (bool, error) {
if clusterAws, ok := cluster.GetAWS(); ok {
if clusterAwsSts, ok := clusterAws.GetSTS(); ok {
if clusterAwsSts.Enabled() {
stsSupportJumpRole, err := utils.DefaultOCMInterface.GetStsSupportJumpRoleARN(cluster.ID())
if err != nil {
return false, fmt.Errorf("failed to get sts support jump role ARN for cluster %v: %w", cluster.ID(), err)
}
supportRoleArn, err := arn.Parse(stsSupportJumpRole)
if err != nil {
return false, fmt.Errorf("failed to parse ARN for jump role %v: %w", stsSupportJumpRole, err)
}
if supportRoleArn.Resource != OldFlowSupportRole {
return true, nil
}
}
}
}
return false, nil
}
Loading

0 comments on commit f3ef69d

Please sign in to comment.