Rick's Dev Notes

Version 0.3.3

Dev notes you can use

Last updated on Tue, 02 Jan 2024 17:28 UTC

AWS

AWS Auth

Credential fetching code

You can use a default credentials flag in your IOptions configuration for the amazon client environment variables.

public async Task<IAmazonS3> CreateClientAsync()
{
	if (_amazonConfig.UseDefaultCredentials)
	{
		return new AmazonS3Client(RegionEndpoint.GetBySystemName(_amazonConfig.Region));
	}
	else
	{
		var stsClient = new AmazonSecurityTokenServiceClient(new AmazonSecurityTokenServiceConfig
		{
			RegionEndpoint = RegionEndpoint.GetBySystemName(_amazonConfig.Region)
		});

		var assumeRoleRequest = new AssumeRoleRequest
		{
			RoleArn = _amazonConfig.RoleArn,
			RoleSessionName = _amazonConfig.RoleSessionName
		};

		var response = await stsClient.AssumeRoleAsync(assumeRoleRequest);
		var credentials = response.Credentials;
		return new AmazonS3Client(credentials, RegionEndpoint.GetBySystemName(_amazonConfig.Region));
	}
}

Credential fetching script

This script depends PowerShell 7 (which you should already be using anyway) because it uses ConvertFrom-Json -AsHashTable.

if ((Get-Command -Name aws.exe | measure).Count -eq 0)
{
	Write-Output "AWS CLI not installed."
	Write-Output "Download and install from https://awscli.amazonaws.com/AWSCLIV2.msi"
	exit 1;
}

if ((Test-Path $pwd\Properties\launchSettings.json) -eq $false)
{
	Write-Output "Run this script from the root of an API project."
	exit 1;
}

# Constants
$configFile = "$env:USERPROFILE\.aws\config"
$settingsFile = "$env:USERPROFILE\.aws\settings"
$startUrl = "https://example.awsapps.com/start#"
$AwsMyRoleId = "123456789000"
$region = "us-east-1"
$format = "json"
$roleName = "MyRole"
$grantType = "urn:ietf:params:oauth:grant-type:device_code"
[datetime]$epoch = '1970-01-01 00:00:00'

$profileContent = @"
[default]
sso_session = sso
sso_account_id = $AwsMyRoleId
sso_role_name = $roleName
region = $region
output = $format
[sso-session sso]
sso_start_url = $startUrl
sso_region = $region
sso_registration_scopes = sso:account:access
"@

# Create the config file
# This can also be done manually by running "aws configure sso"
if (!(Test-Path $configFile -PathType Leaf))
{
	$null = New-Item -Path $configFile -Force
	$profileContent | Set-Content $configFile
}

# login to AWS SSO
# 3 hour session
# tracking this session expiry is difficult so we will just re-login every time
Write-Output "Logging into AWS SSO; allow access on browser..."
$null = aws sso login
Write-Output "Successfully logged into AWS SSO."

# initialize the settings file
If (!(Test-Path $settingsFile))
{
	$null = New-Item -Path $settingsFile -Force
	$settings = New-Object -TypeName PSObject
	$settings | Add-Member -MemberType NoteProperty -Name ClientId -Value ""
	$settings | Add-Member -MemberType NoteProperty -Name ClientSecret -Value ""
	$settings | Add-Member -MemberType NoteProperty -Name ClientExpiry -Value $epoch
	$settings | Add-Member -MemberType NoteProperty -Name AccessToken -Value ""
	$settings | Add-Member -MemberType NoteProperty -Name AccessTokenExpiry -Value $epoch
	$settings | ConvertTo-Json -depth 32 | Set-Content $settingsFile
}

# Read the settings file
$settings = Get-Content $settingsFile -Raw | ConvertFrom-Json
$clientId = $settings.ClientId
$clientSecret = $settings.ClientSecret
$clientExpiry = $settings.ClientExpiry
$accessToken = $settings.AccessToken
$accessTokenExpiry = $settings.AccessTokenExpiry

# Get your account Id
$accountId = aws sts get-caller-identity --query Account --output text
if (-not [bool]$accountId) { Write-Output "Unable to get account Id." exit 1; }

# Register a new client
# 3 month expiry
if ($clientExpiry -lt (Get-Date))
{
	Write-Output ""
	Write-Output "Registering client with AWS."
	$hostname = hostname
	$client = aws sso-oidc register-client --client-name $hostname --client-type public | ConvertFrom-Json
	if (-not [bool]$client) { Write-Output "Unable to get register client." exit 1; }
	$clientId = $client.clientId
	$clientSecret = $client.clientSecret
	$clientExpiry = $epoch.AddSeconds($client.clientSecretExpiresAt)
	Write-Output "Client successfully registered."
}

# Set up the authorization code flow
# 7 hour expiry
if ($accessTokenExpiry -lt (Get-Date))
{
	Write-Output ""
	Write-Output "Starting device authorization code flow."
	$device = aws sso-oidc start-device-authorization --client-id $clientId --client-secret $clientSecret --start-url $startUrl | ConvertFrom-Json
	if (-not [bool]$device) { Write-Output "Unable to get start device authorization." exit 1; }
	$deviceCode = $device.deviceCode
	start $device.verificationUriComplete
	Write-Output "Before continuing, authorize this device by allowing access on browser..."
	Write-Output "Press [Enter] when completed."
	$null = [System.Console]::ReadKey()
	$createdToken = aws sso-oidc create-token --client-id $clientId --client-secret $clientSecret --grant-type $grantType --device-code $deviceCode | ConvertFrom-Json
	if (-not [bool]$createdToken) { Write-Output "Unable to get create token." exit 1; }
	$accessToken = $createdToken.accessToken
	$accessTokenExpiry = (Get-Date).AddSeconds($createdToken.expiresIn)
	Write-Output "Successfully set up authorization code flow for this device."
}

# Get the role credentials
Write-Output ""
Write-Output "Generating role credentials."
$credentials = aws sso get-role-credentials --role-name $roleName --account-id $accountId --access-token $accessToken | ConvertFrom-Json
if (-not [bool]$credentials) { Write-Output "Unable to get role credentials." exit 1; }
$key = $credentials.roleCredentials.accessKeyId
$secret = $credentials.roleCredentials.secretAccessKey
$token = $credentials.roleCredentials.sessionToken
$tokenExpiry = $epoch.AddSeconds($credentials.roleCredentials.expiration / 1000)
Write-Output "Successfully generated role credentials."

# Write credentials to launchsettings.Json
Write-Output ""
Write-Output "Writing credentials to launchsettings.json."
$launchSettings = Get-Content $pwd\Properties\launchSettings.json -Raw | ConvertFrom-Json -AsHashTable
if (-not [bool]$launchSettings) { Write-Output "Unable to get launchsettings.json." exit 1; }
foreach ($profileKey in $launchSettings.profiles.Keys)
{
	$profile = $launchSettings.profiles[$profileKey]

	if ($profile.ContainsKey("environmentVariables") -eq $false) { $profile.Add("environmentVariables", @{}) }
	if ($profile.environmentVariables.ContainsKey("AWS_ACCESS_KEY_ID") -eq $false) { $profile.environmentVariables.Add("AWS_ACCESS_KEY_ID", "") }
	if ($profile.environmentVariables.ContainsKey("AWS_SECRET_ACCESS_KEY") -eq $false) { $profile.environmentVariables.Add("AWS_SECRET_ACCESS_KEY", "") }
	if ($profile.environmentVariables.ContainsKey("AWS_SESSION_TOKEN") -eq $false) { $profile.environmentVariables.Add("AWS_SESSION_TOKEN", "") }
	
	$profile.environmentVariables.AWS_ACCESS_KEY_ID = $key
	$profile.environmentVariables.AWS_SECRET_ACCESS_KEY = $secret
	$profile.environmentVariables.AWS_SESSION_TOKEN = $token
}
$launchSettings | ConvertTo-Json -depth 32 | Set-Content $pwd\Properties\launchSettings.json
Write-Output "Successfully wrote credentials to launchsettings.json."

# Save the settings file
$settings.ClientId = $clientId
$settings.ClientSecret = $clientSecret
$settings.ClientExpiry = $clientExpiry
$settings.AccessToken = $accessToken
$settings.AccessTokenExpiry = $accessTokenExpiry
$settings | ConvertTo-Json -depth 32 | Set-Content $settingsFile

Write-Output ""
Write-Output "Ready! Your session token will expire on $tokenExpiry."
Write-Output ""