Skip to content

Commit

Permalink
add '--use-credential-process' to write command (#443)
Browse files Browse the repository at this point in the history
Make it easier for people to start using BMX in `credential_process`,
and reduce user errors.

https://d2l.slack.com/archives/G4P099831/p1705333949277619
  • Loading branch information
cfbao authored Jan 17, 2024
1 parent 75f1728 commit 2c4493b
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 25 deletions.
27 changes: 23 additions & 4 deletions src/D2L.Bmx/AwsCredsCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@

namespace D2L.Bmx;

internal record AwsCredentialsInfo(
string Account,
string Role,
int Duration,
AwsCredentials Credentials
);

internal class AwsCredsCreator(
IAwsClient awsClient,
IConsolePrompter consolePrompter,
IAwsCredentialCache awsCredentialCache,
BmxConfig config
) {
public async Task<AwsCredentials> CreateAwsCredsAsync(
public async Task<AwsCredentialsInfo> CreateAwsCredsAsync(
AuthenticatedOktaApi oktaApi,
string? account,
string? role,
Expand Down Expand Up @@ -50,7 +57,11 @@ bool cache
);

if( cachedCredentials is not null ) {
return cachedCredentials;
return new(
Account: account,
Role: role,
Duration: duration.Value,
Credentials: cachedCredentials );
}
}

Expand Down Expand Up @@ -92,7 +103,11 @@ bool cache
);

if( cachedCredentials is not null ) {
return cachedCredentials;
return new(
Account: account,
Role: role,
Duration: duration.Value,
Credentials: cachedCredentials );
}
}

Expand All @@ -117,6 +132,10 @@ bool cache
);
}

return credentials;
return new(
Account: account,
Role: role,
Duration: duration.Value,
Credentials: credentials );
}
}
10 changes: 8 additions & 2 deletions src/D2L.Bmx/ParameterDescriptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ internal static class ParameterDescriptions {
public const string Role = "AWS role name";
public const string Duration = "AWS session duration in minutes";
public const string Profile = "AWS profile name";
public const string Output = "Custom path to the AWS credentials file";
public const string Output =
"Custom path to the AWS credentials file, or the AWS config file if '--use-credential-process' is supplied";
public const string Format = "Output format of AWS credentials";
public const string NonInteractive = "Run non-interactively without showing any prompts";
public const string CacheAwsCredentials = "Enables Cache for AWS tokens";
public const string CacheAwsCredentials =
"Enables Cache for AWS tokens. Implied if '--use-credential-process' is supplied";
public const string UseCredentialProcess = """
Write BMX command to AWS profile, so that AWS tools & SDKs using the profile will source credentials from BMX.
See https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html.
""";
}
4 changes: 2 additions & 2 deletions src/D2L.Bmx/PrintHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ bool cacheAwsCredentials
nonInteractive: nonInteractive,
ignoreCache: false
);
var awsCreds = await awsCredsCreator.CreateAwsCredsAsync(
var awsCreds = ( await awsCredsCreator.CreateAwsCredsAsync(
oktaApi: oktaApi,
account: account,
role: role,
duration: duration,
nonInteractive: nonInteractive,
cache: cacheAwsCredentials
);
) ).Credentials;

if( string.Equals( format, PrintFormat.Bash, StringComparison.OrdinalIgnoreCase ) ) {
PrintBash( awsCreds );
Expand Down
7 changes: 6 additions & 1 deletion src/D2L.Bmx/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@
var profileOption = new Option<string>(
name: "--profile",
description: ParameterDescriptions.Profile );
var useCredentialProcessOption = new Option<bool>(
name: "--use-credential-process",
description: ParameterDescriptions.UseCredentialProcess );

var writeCommand = new Command( "write", "Write AWS credentials to the credentials file" ) {
accountOption,
Expand All @@ -164,6 +167,7 @@
userOption,
nonInteractiveOption,
cacheAwsCredentialsOption,
useCredentialProcessOption,
};

writeCommand.SetHandler( ( InvocationContext context ) => {
Expand Down Expand Up @@ -193,7 +197,8 @@
nonInteractive: context.ParseResult.GetValueForOption( nonInteractiveOption ),
output: context.ParseResult.GetValueForOption( outputOption ),
profile: context.ParseResult.GetValueForOption( profileOption ),
cacheAwsCredentials: context.ParseResult.GetValueForOption( cacheAwsCredentialsOption )
cacheAwsCredentials: context.ParseResult.GetValueForOption( cacheAwsCredentialsOption ),
useCredentialProcess: context.ParseResult.GetValueForOption( useCredentialProcessOption )
);
} );

Expand Down
52 changes: 36 additions & 16 deletions src/D2L.Bmx/WriteHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@ public async Task HandleAsync(
bool nonInteractive,
string? output,
string? profile,
bool cacheAwsCredentials
bool cacheAwsCredentials,
bool useCredentialProcess
) {
cacheAwsCredentials = cacheAwsCredentials || useCredentialProcess;

var oktaApi = await oktaAuth.AuthenticateAsync(
org: org,
user: user,
nonInteractive: nonInteractive,
ignoreCache: false
);
var awsCreds = await awsCredsCreator.CreateAwsCredsAsync(
var awsCredsInfo = await awsCredsCreator.CreateAwsCredsAsync(
oktaApi: oktaApi,
account: account,
role: role,
Expand All @@ -48,24 +51,41 @@ bool cacheAwsCredentials
if( !string.IsNullOrEmpty( output ) && !Path.IsPathRooted( output ) ) {
output = "./" + output;
}
string credentialsFilePath = new SharedCredentialsFile( output ).FilePath;
string credentialsFolderPath = Path.GetDirectoryName( credentialsFilePath )
?? throw new BmxException( "Invalid AWS credentials file path" );
if( !Directory.Exists( credentialsFolderPath ) ) {
Directory.CreateDirectory( credentialsFolderPath );
if( string.IsNullOrEmpty( output ) ) {
output = useCredentialProcess
? SharedCredentialsFile.DefaultConfigFilePath
: SharedCredentialsFile.DefaultFilePath;
}
if( !File.Exists( credentialsFilePath ) ) {
using( File.Create( credentialsFilePath ) ) { };

string outputFolder = Path.GetDirectoryName( output )
?? throw new BmxException( "Invalid output path" );
Directory.CreateDirectory( outputFolder );
if( !File.Exists( output ) ) {
using( File.Create( output ) ) { };
}

var data = parser.ReadFile( credentialsFilePath );
if( !data.Sections.ContainsSection( profile ) ) {
data.Sections.AddSection( profile );
var data = parser.ReadFile( output );
if( useCredentialProcess ) {
string sectionName = $"profile {profile}";
if( !data.Sections.ContainsSection( sectionName ) ) {
data.Sections.AddSection( sectionName );
}
data[sectionName]["credential_process"] =
"bmx print --format json --cache --non-interactive"
+ $" --org \"{oktaApi.Org}\""
+ $" --user \"{oktaApi.User}\""
+ $" --account \"{awsCredsInfo.Account}\""
+ $" --role \"{awsCredsInfo.Role}\""
+ $" --duration {awsCredsInfo.Duration}";
} else {
if( !data.Sections.ContainsSection( profile ) ) {
data.Sections.AddSection( profile );
}
data[profile]["aws_access_key_id"] = awsCredsInfo.Credentials.AccessKeyId;
data[profile]["aws_secret_access_key"] = awsCredsInfo.Credentials.SecretAccessKey;
data[profile]["aws_session_token"] = awsCredsInfo.Credentials.SessionToken;
}
data[profile]["aws_access_key_id"] = awsCreds.AccessKeyId;
data[profile]["aws_secret_access_key"] = awsCreds.SecretAccessKey;
data[profile]["aws_session_token"] = awsCreds.SessionToken;

parser.WriteFile( credentialsFilePath, data, new UTF8Encoding( false ) );
parser.WriteFile( output, data, new UTF8Encoding( encoderShouldEmitUTF8Identifier: false ) );
}
}

0 comments on commit 2c4493b

Please sign in to comment.