Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fedramp: Add environment-specific configuration #702

Merged
merged 5 commits into from
Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/create/accountroles/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ func createRoles(r *rosa.Runtime, prefix, permissionsBoundary, accountID, env st
policyDetail := policies[filename]

policy := aws.InterpolatePolicyDocument(policyDetail, map[string]string{
"aws_account_id": aws.JumpAccounts[env],
"partition": aws.GetPartition(),
"aws_account_id": aws.GetJumpAccount(env),
})
r.Reporter.Debugf("Creating role '%s'", name)
roleARN, err := r.AWSClient.EnsureRole(name, policy, permissionsBoundary,
Expand Down
17 changes: 9 additions & 8 deletions cmd/create/cluster/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
installLogs "github.com/openshift/rosa/cmd/logs/install"
"github.com/openshift/rosa/pkg/arguments"
"github.com/openshift/rosa/pkg/aws"
"github.com/openshift/rosa/pkg/fedramp"
"github.com/openshift/rosa/pkg/helper"
"github.com/openshift/rosa/pkg/interactive"
"github.com/openshift/rosa/pkg/interactive/confirm"
Expand All @@ -48,7 +49,7 @@ import (
)

//nolint
var kmsArnRE = regexp.MustCompile(`^arn:aws:kms:[\w-]+:\d{12}:key\/mrk-[0-9a-f]{32}$|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)
var kmsArnRE = regexp.MustCompile(`^arn:aws[\w-]*:kms:[\w-]+:\d{12}:key\/mrk-[0-9a-f]{32}$|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)

var args struct {
// Watch logs during cluster installation
Expand Down Expand Up @@ -562,7 +563,7 @@ func run(cmd *cobra.Command, _ []string) {
os.Exit(1)
}

isSTS := args.sts || args.roleARN != ""
isSTS := args.sts || args.roleARN != "" || fedramp.Enabled()
isIAM := cmd.Flags().Changed("sts") && !isSTS

if interactive.Enabled() && (!isSTS && !isIAM) {
Expand Down Expand Up @@ -1123,15 +1124,15 @@ func run(cmd *cobra.Command, _ []string) {

// Cluster privacy:
useExistingVPC := false
privateLink := args.privateLink
privateLink := args.privateLink || fedramp.Enabled()
private := args.private

privateLinkWarning := "Once the cluster is created, this option cannot be changed."
if isSTS {
privateLinkWarning = fmt.Sprintf("STS clusters can only be private if AWS PrivateLink is used. %s ",
privateLinkWarning)
}
if interactive.Enabled() {
if interactive.Enabled() && !fedramp.Enabled() {
privateLink, err = interactive.GetBool(interactive.Input{
Question: "PrivateLink cluster",
Help: fmt.Sprintf("%s %s", cmd.Flags().Lookup("private-link").Usage, privateLinkWarning),
Expand All @@ -1141,7 +1142,7 @@ func run(cmd *cobra.Command, _ []string) {
r.Reporter.Errorf("Expected a valid private-link value: %s", err)
os.Exit(1)
}
} else if privateLink || (isSTS && private) {
} else if (privateLink || (isSTS && private)) && !fedramp.Enabled() {
r.Reporter.Warnf("You are choosing to use AWS PrivateLink for your cluster. %s", privateLinkWarning)
if !confirm.Confirm("use AWS PrivateLink for cluster '%s'", clusterName) {
os.Exit(0)
Expand Down Expand Up @@ -1638,8 +1639,8 @@ func run(cmd *cobra.Command, _ []string) {
os.Exit(1)
}

fips := args.fips
if interactive.Enabled() && fips {
fips := args.fips || fedramp.Enabled()
if interactive.Enabled() && fips && !fedramp.Enabled() {
fips, err = interactive.GetBool(interactive.Input{
Question: "Enable FIPS support",
Help: cmd.Flags().Lookup("fips").Usage,
Expand Down Expand Up @@ -2022,7 +2023,7 @@ func getOperatorRoleArn(prefix string, operator *cmv1.STSOperator, creator *aws.
if len(role) > 64 {
role = role[0:64]
}
return fmt.Sprintf("arn:aws:iam::%s:role/%s", creator.AccountID, role)
return aws.GetRoleARN(creator.AccountID, role)
}

func getAccountRolePrefix(roleARN string, role aws.AccountRole) (string, error) {
Expand Down
6 changes: 4 additions & 2 deletions cmd/create/ocmrole/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ func createRoles(r *rosa.Runtime, prefix string, roleName string,
filename := fmt.Sprintf("sts_%s_trust_policy", aws.OCMRolePolicyFile)
policyDetail := policies[filename]
policy := aws.InterpolatePolicyDocument(policyDetail, map[string]string{
"aws_account_id": aws.JumpAccounts[env],
"partition": aws.GetPartition(),
"aws_account_id": aws.GetJumpAccount(env),
"ocm_organization_id": orgID,
})

Expand Down Expand Up @@ -394,7 +395,8 @@ func generateOcmRolePolicyFiles(r *rosa.Runtime, env string, orgID string, isAdm

policyDetail := policies[filename]
policy := aws.InterpolatePolicyDocument(policyDetail, map[string]string{
"aws_account_id": aws.JumpAccounts[env],
"partition": aws.GetPartition(),
"aws_account_id": aws.GetJumpAccount(env),
"ocm_organization_id": orgID,
})
r.Reporter.Debugf("Saving '%s' to the current directory", filename)
Expand Down
2 changes: 1 addition & 1 deletion cmd/create/operatorroles/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ func getPolicyARN(accountID string, prefix string, namespace string, name string
if len(policy) > 64 {
policy = policy[0:64]
}
return fmt.Sprintf("arn:aws:iam::%s:policy/%s", accountID, policy)
return aws.GetPolicyARN(accountID, policy)
}

func validateOperatorRoles(r *rosa.Runtime, cluster *cmv1.Cluster) ([]string, error) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/create/service/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,5 +484,5 @@ func getOperatorRoleArn(prefix string, operator *cmv1.STSOperator, creator *aws.
if len(role) > 64 {
role = role[0:64]
}
return fmt.Sprintf("arn:aws:iam::%s:role/%s", creator.AccountID, role)
return aws.GetRoleARN(creator.AccountID, role)
}
8 changes: 5 additions & 3 deletions cmd/create/userrole/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func buildCommands(prefix string, userName string, accountID string, env string,
commands := []string{}
roleName := aws.GetUserRoleName(prefix, aws.OCMUserRole, userName)

roleARN := fmt.Sprintf("arn:aws:iam::%s:role/%s", accountID, roleName)
roleARN := aws.GetRoleARN(accountID, roleName)
iamTags := fmt.Sprintf(
"Key=%s,Value=%s Key=%s,Value=%s Key=%s,Value=%s",
tags.RolePrefix, prefix,
Expand Down Expand Up @@ -253,7 +253,8 @@ func createRoles(r *rosa.Runtime,
filename := fmt.Sprintf("sts_%s_trust_policy", aws.OCMUserRolePolicyFile)
policyDetail := policies[filename]
policy := aws.InterpolatePolicyDocument(policyDetail, map[string]string{
"aws_account_id": aws.JumpAccounts[env],
"partition": aws.GetPartition(),
"aws_account_id": aws.GetJumpAccount(env),
"ocm_account_id": accountID,
})

Expand Down Expand Up @@ -285,7 +286,8 @@ func generateUserRolePolicyFiles(reporter *rprtr.Object, env string, accountID s
filename := fmt.Sprintf("sts_%s_trust_policy", aws.OCMUserRolePolicyFile)
policyDetail := policies[filename]
policy := aws.InterpolatePolicyDocument(policyDetail, map[string]string{
"aws_account_id": aws.JumpAccounts[env],
"partition": aws.GetPartition(),
"aws_account_id": aws.GetJumpAccount(env),
"ocm_account_id": accountID,
})

Expand Down
1 change: 0 additions & 1 deletion cmd/initialize/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ func init() {
flags.AddFlagSet(login.Cmd.Flags())

arguments.AddProfileFlag(flags)
arguments.AddRegionFlag(flags)

confirm.AddFlag(flags)
}
Expand Down
73 changes: 57 additions & 16 deletions cmd/login/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ import (
"github.com/spf13/cobra"

"github.com/openshift/rosa/cmd/logout"
"github.com/openshift/rosa/pkg/arguments"
"github.com/openshift/rosa/pkg/config"
"github.com/openshift/rosa/pkg/fedramp"
"github.com/openshift/rosa/pkg/interactive"
"github.com/openshift/rosa/pkg/ocm"
rprtr "github.com/openshift/rosa/pkg/reporter"
"github.com/openshift/rosa/pkg/rosa"
)

// #nosec G101
const uiTokenPage = "https://console.redhat.com/openshift/token/rosa"
var uiTokenPage string = "https://console.redhat.com/openshift/token/rosa"

var reAttempt bool

Expand Down Expand Up @@ -118,32 +121,51 @@ func init() {
"Enables insecure communication with the server. This disables verification of TLS "+
"certificates and host names.",
)
arguments.AddRegionFlag(flags)
fedramp.AddFlag(flags)
}

func run(cmd *cobra.Command, argv []string) {
r := rosa.NewRuntime()

// Check mandatory options:
if args.env == "" {
env := args.env
if env == "" {
r.Reporter.Errorf("Option '--env' is mandatory")
os.Exit(1)
}

// Load the configuration file:
cfg, err := ocm.Load()
cfg, err := config.Load()
if err != nil {
r.Reporter.Errorf("Failed to load config file: %v", err)
os.Exit(1)
}
if cfg == nil {
cfg = new(ocm.Config)
cfg = new(config.Config)
}

token := args.token

// Determine if we should be using the FedRAMP environment:
if fedramp.HasFlag(cmd) ||
(cfg.FedRAMP && token == "") ||
fedramp.IsGovRegion(arguments.GetRegion()) ||
config.IsEncryptedToken(token) {
fedramp.Enable()
// Always default to prod
if env == sdk.DefaultURL {
env = "production"
}
uiTokenPage = fedramp.LoginURLs[env]
} else {
fedramp.Disable()
}

haveReqs := token != ""

// Verify environment variables:
if !haveReqs && !reAttempt {
if !haveReqs && !reAttempt && !fedramp.Enabled() {
token = os.Getenv("ROSA_TOKEN")
if token == "" {
token = os.Getenv("OCM_TOKEN")
Expand Down Expand Up @@ -180,7 +202,17 @@ func run(cmd *cobra.Command, argv []string) {
os.Exit(1)
}

// Apply the default OpenID details if not explicitly provided by the user:
// Red Hat SSO does not issue encrypted refresh tokens, but AWS Cognito does. If the token
// is encrypted we can safely assume that the user is trying to use the FedRAMP environment.
if config.IsEncryptedToken(token) {
fedramp.Enable()
}

// Apply the default configuration details if not explicitly provided by the user:
gatewayURL, ok := ocm.URLAliases[env]
if !ok {
gatewayURL = env
}
tokenURL := sdk.DefaultTokenURL
if args.tokenURL != "" {
tokenURL = args.tokenURL
Expand All @@ -189,12 +221,20 @@ func run(cmd *cobra.Command, argv []string) {
if args.clientID != "" {
clientID = args.clientID
}

// If the value of the `--env` is any of the aliases then replace it with the corresponding
// real URL:
gatewayURL, ok := ocm.URLAliases[args.env]
if !ok {
gatewayURL = args.env
// Override configuration details for FedRAMP:
if fedramp.Enabled() {
gatewayURL, ok = fedramp.URLAliases[env]
if !ok {
gatewayURL = env
}
tokenURL, ok = fedramp.TokenURLs[env]
if !ok {
tokenURL = args.tokenURL
}
clientID, ok = fedramp.ClientIDs[env]
if !ok {
clientID = args.clientID
}
}

// Update the configuration with the values given in the command line:
Expand All @@ -204,14 +244,15 @@ func run(cmd *cobra.Command, argv []string) {
cfg.Scopes = args.scopes
cfg.URL = gatewayURL
cfg.Insecure = args.insecure
cfg.FedRAMP = fedramp.Enabled()

if token != "" {
if ocm.IsEncryptedToken(token) {
if config.IsEncryptedToken(token) {
cfg.AccessToken = ""
cfg.RefreshToken = token
} else {
// If a token has been provided parse it:
jwtToken, err := ocm.ParseToken(token)
jwtToken, err := config.ParseToken(token)
if err != nil {
r.Reporter.Errorf("Failed to parse token '%s': %v", token, err)
os.Exit(1)
Expand Down Expand Up @@ -263,7 +304,7 @@ func run(cmd *cobra.Command, argv []string) {
// Save the configuration:
cfg.AccessToken = accessToken
cfg.RefreshToken = refreshToken
err = ocm.Save(cfg)
err = config.Save(cfg)
if err != nil {
r.Reporter.Errorf("Failed to save config file: %v", err)
os.Exit(1)
Expand Down Expand Up @@ -328,7 +369,7 @@ func Call(cmd *cobra.Command, argv []string, reporter *rprtr.Object) error {

// Verify if user is already logged in:
isLoggedIn := false
cfg, err := ocm.Load()
cfg, err := config.Load()
if err != nil {
return fmt.Errorf("Failed to load config file: %v", err)
}
Expand Down
9 changes: 5 additions & 4 deletions cmd/logout/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ limitations under the License.
package logout

import (
rprtr "github.com/openshift/rosa/pkg/reporter"
"github.com/spf13/cobra"
"os"

"github.com/openshift/rosa/pkg/ocm"
"github.com/spf13/cobra"

"github.com/openshift/rosa/pkg/config"
rprtr "github.com/openshift/rosa/pkg/reporter"
)

var Cmd = &cobra.Command{
Expand All @@ -34,7 +35,7 @@ var Cmd = &cobra.Command{
func run(cmd *cobra.Command, argv []string) {
reporter := rprtr.CreateReporterOrExit()
// Remove the configuration file:
err := ocm.Remove()
err := config.Remove()
if err != nil {
reporter.Errorf("Failed to remove config file: %v", err)
os.Exit(1)
Expand Down
5 changes: 3 additions & 2 deletions cmd/whoami/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/openshift/rosa/pkg/arguments"
"github.com/openshift/rosa/pkg/aws"
"github.com/openshift/rosa/pkg/config"
"github.com/openshift/rosa/pkg/ocm"
"github.com/openshift/rosa/pkg/rosa"
)
Expand Down Expand Up @@ -55,7 +56,7 @@ func run(_ *cobra.Command, _ []string) {
}

// Load the configuration file:
cfg, err := ocm.Load()
cfg, err := config.Load()
if err != nil {
r.Reporter.Errorf("Failed to load config file: %v", err)
os.Exit(1)
Expand Down Expand Up @@ -132,7 +133,7 @@ func run(_ *cobra.Command, _ []string) {
fmt.Println()
}

func getAccountDataFromToken(cfg *ocm.Config) (*amsv1.Account, error) {
func getAccountDataFromToken(cfg *config.Config) (*amsv1.Account, error) {
firstName, err := cfg.GetData("first_name")
if err != nil {
return nil, err
Expand Down
7 changes: 7 additions & 0 deletions pkg/aws/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/aws/aws-sdk-go/service/sts"
"github.com/aws/aws-sdk-go/service/sts/stsiface"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
"github.com/openshift/rosa/pkg/fedramp"
"github.com/openshift/rosa/pkg/reporter"
"github.com/sirupsen/logrus"

Expand Down Expand Up @@ -264,6 +265,12 @@ func (b *ClientBuilder) Build() (Client, error) {
b.region = aws.String(region)
}

if fedramp.IsGovRegion(*b.region) {
fedramp.Enable()
} else if fedramp.Enabled() {
return nil, fmt.Errorf("Failed to connect to AWS. Use a GovCloud region in your profile")
}

// Create the AWS session:
if b.credentials != nil {
sess, err = b.BuildSessionWithOptionsCredentials(b.credentials)
Expand Down
Loading