-->

aws twilio, sendgrid, route53

When you use Twilio SendGrid for sending emails, you have two options to verify your sender addresses:

  • Single sender verification

  • Domain authentication

If you select the first option, you need to confirm you have access to that address by clicking on the confirmation link that will be sent to that address. Domain authentication, however, requires access to the domain’s DNS records. In this article, you will learn how to achieve this when your domain is hosted on AWS Route 53.

Prerequisites

You can create a free AWS account, but hosted domains are not covered in Free Tier. A hosted domain costs $0.50 per month, but for testing purposes, you will not be charged if you delete it within 12 hours of creation. For further details, please check Route 53 pricing.

Start Domain Authentication

In your SendGrid account, go to Sender Authentication.

Click the Get Started button in the Authenticate Your Domain section:

In the DNS host list, select Amazon Route 53:

Authenticate Your Domain page showing Amazon Route 53 as host

Leave the branding option as No and click the Next button at the bottom right.

On the next page, enter your domain in the From Domain input:

Authenticate Your Domain page asking for the domain to authenticate

Click Next.

To verify your domain ownership, you will be asked to add CNAME records to your domain:

CNAME records are displayed to be added to the DNS

Update DNS Records

Now open the hosted zones in the AWS Route 53 console in another tab.

Click your domain and click the Create record button:

Route53 records page showing the Create record button

Select CNAME as the record type and enter the name before the domain as the record name.

Then, paste the value in the Value area:

Create record page showing the details of the new DNS record

Click Create records.

Repeat this step for all the CNAME records displayed on your SendGrid account.

Verify DNS Records

Now go back to the Install DNS Records page on your SendGrid account.

Tick I’ve added these records checkbox and click the Verify button.

DNS records may take a few minutes to propagate, so it may take a few tries until SendGrid verifies the new entries in your domain.

Once done, you should see a success message to confirm your domain has been verified:

Verify Your Domain page showing the success message

You should see the verified domain on the Sender Authentication page too:

Sender Authentication page shows the verified domain

Test sending email

If you already don’t have a mechanism to test your set-up, you can follow the steps below. The example below demonstrates creating a C# console application to send emails. If dotnet is not your cup of tea, you can visit SendGrid documentation for examples in many other languages.

Go to the API Keys page and click the Create API key button.

Give a meaningful name to the key and select Full Access.

Click Create & View.

Click the API key displayed on your screen to copy it to your clipboard. This is your one and only chance to save your key, so make sure to store it in a secure place.

Create a new console application by running the following command:

dotnet new console -o SendGrid.DomainAuthTest

Open the project in your IDE.

Add your API key as an environment variable:

export SENDGRID_API_KEY={your key}

Change to your project folder in the terminal and add SendGrid SDK via NuGet:

dotnet add package SendGrid

Replace the contents of the Program.cs with the following code by replacing the sender and recipient addresses to match your setup:

using SendGrid;
using SendGrid.Helpers.Mail;

var apiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
var client = new SendGridClient(apiKey);
var from = new EmailAddress("any-address-would-do@yourdomain.com", "Verified Domain Test");
var subject = "This is sent from a random name from the verified domain";
var to = new EmailAddress("{ your recipient address }", "Recipient");
var plainTextContent = "Text content";
var htmlContent = "<strong>HTML content</strong>";
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
await client.SendEmailAsync(msg);

Run the application by running the following command:

dotnet run

You should now receive the test email from the email address you specified.

Conclusion

Verifying the domain may be more cumbersome than verifying a single address, but once you’ve done it, you can send emails from any address you want. Of course, this doesn’t allow you to receive replies which require you to have valid inboxes, which will be discussed in other articles.

aws security, mfa, yubikey

Multi-factor authentication (MFA) provides an extra layer of security to your accounts and helps prevent unauthorized access, even if a user’s access key is compromised. It’s fairly straightforward to add MFA to use AWS Management Console, which is highly recommended. It involves a few more steps when using the CLI, which you will see in this tutorial.

When using AWS CLI, developers generally store their IAM keys in plaintext on their computers. In the previous article, we discussed how to rotate AWS access keys. This is a good practice, but anyone with access to those credentials can still impersonate the owner before they are revoked. These keys are generally quite powerful and allow access to critical parts of the system. In this tutorial, you will learn how to add Yubikey support for using AWS CLI so that even if the IAM key is compromised, the hackers can’t use it without access to the physical security token.

Prerequisites

Set up the environment

To test using a Yubikey with AWS CLI, first, you’ll need an IAM user.

Log in to AWS Management Console and go to Identity and Access Management (IAM).

Click Users in the menu and then click the Add Users button.

Enter demo_user as the user name and click Next.

Click Next again on the Permissions page and click Create user on the review page.

After creating your user, click on the user name and switch to the Security credentials tab.

Scroll down to Access keys and click Create access key.

Select Command Line Interface (CLI) for your intended usage, tick the I understand… checkbox at the bottom and click Next.

Command Line Interface (CLI) is selected as the intended use for the key

Click Create access key on the next page.

In your AWS credentials file (~/.aws/credentials), copy and paste your access and secret access keys into a new profile with the same name so it looks like this:

Click Done to finish the key creation process.

Open a terminal and run the following command:

aws s3 ls --profile demo_user

You should see Access Denied error as you haven’t granted any permissions to this access key.

Terminal showing Access Denied error while trying to list the buckets

Now, create a role that gives this access to the user.

Click Roles and Create role.

Select Custom trust policy and paste the following policy. Make sure to replace <YOUR ACCOUNT NUMBER> with the actual value.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Statement1",
      "Effect": "Allow",
      "Principal": { "AWS":"arn:aws:iam::<YOUR ACCOUNT NUMBER>:user/demo_user" },
      "Action": "sts:AssumeRole",
      "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } }
    }
  ]
}

Click Next.

On the Add permissions page, search S3 and tick the checkbox next to the AmazonS3ReadOnlyAccess policy.

Click Next.

Enter s3-read-only-mfa-role as the role name and click Create role.

As you can see in the role policy, there is a condition for the MFA present. In the next section, you will add that to the user.

Add Yubikey to the User

Open the user’s Security Credentials tab and scroll to the Multi-factor authentication (MFA) section.

Click the Assign MFA device button.

On the Select MFA device page, enter yubikey as the device name.

Select the Authenticator app as the device type. This is a bit counter-intuitive as Yubikey is listed as a security key, but you will generate a Time-based one-time password (TOTP) with your Yubikey, so make sure to select this option.

Select MFA device page showing yubikey entered as device name and Authenticator app selected as device type.

Click Next.

On the Set up device page, click the Show secret key link.

Set up device page showing the Show secret key link

As you will be using the CLI, the QR code will not do it in this case, but the QR code is just a visual representation of the same secret key anyway.

Copy the secret key displayed on your screen and run the following command in a terminal:

ykman oath accounts add -t yubikey { YOUR SECRET KEY }

Make sure to use the -t parameter as it enforces touching the key. It adds extra security as the codes cannot be generated without physical access.

It’s now time to generate 2 time-based codes. So to achieve this, run the following command:

ykman oath accounts code yubikey

Copy the 6-digit integer and paste it into the MFA code 1 field.

Keep running the command above to generate a second code. It may take a few tries as it’s time-based. For example, my attempt looked like this:

Terminal window showing ykman commands to add the key and generate the codes

Now it’s time to tie them all together. For this, you will need the following to your AWS config file (~/.aws/config):

[profile demo_user]
source_profile = demo_user
mfa_serial = arn:aws:iam::<YOUR ACCOUNT NUMBER>:mfa/yubikey
role_arn = arn:aws:iam::<YOUR ACCOUNT NUMBER>:role/s3-read-only-mfa-role

Make sure to replace <YOUR ACCOUNT NUMBER> with the actual value in both places.

Rerun the same test command to see if it behaves differently:

aws s3 ls --profile demo_user

This time you should see the CLI asking for an MFA code:

Terminal showing AWS CLI asking for an MFA code

Press Ctrl + C to exit this, as you don’t have the code at the moment. To generate the code, run the same command you used while registering the MFA device:

ykman oath accounts code yubikey

Then, rerun the AWS command and copy/paste the 6-digit code generated by Yubikey and press enter. This time you should see the successful results:

Terminal window showing successful results after MFA code has been entered

By default, the temporary credentials are valid for 1 hour. You can change this value in the role settings by clicking the Edit button in the role summary section.

Make sure NOT to choose for a very long time, as the temporary security credentials cannot be revoked.

If you want to double-check that you’re really using these temporary credentials for the role you created, run the following command:

aws sts get-caller-identity --profile demo_user

You can see in the Arn field the assumed role is s3-read-only-mfa-role.

To further test, attempt to create a new bucket by running the following command:

aws s3 mb s3://my-demo-bucket-56345765 --region us-east-1 --profile demo_user

You should get an Access Denied error as you only have read-only access to the S3 service.

If you want to revoke the credentials locally, you can delete the AWS CLI cache by running the following command:

 rm -r ~/.aws/cli/cache

Conclusion

In this tutorial, you learned how to enforce using MFA with Yubikey for your CLI operations. This way, the access key you store in your credentials file is just used to assume the role with the actual permissions. The stored keys have no permissions at all. Therefore even if they are compromised, as long as the attacker doesn’t have access to the physical security key, they will not be useful to them. I hope you found the article helpful in improving your AWS account security.

aws powershell, security

If you are working with AWS, it’s considered a good practice to rotate AWS access keys. When working with AWS resources, I try to use role-based access controls, but it’s not always possible to stay in the AWS ecosystem. At the very least, I use my IAM user credentials locally in my dev environment. The ability to replace these keys easily can help increase your AWS account’s security. In this article, you will implement a PowerShell script to rotate your IAM access keys. It works with multiple profiles, so if all your passwords are compromised in a security breach (such as the LastPass incident) you can replace all your IAM keys by simply running your script.

Prerequisites

Why rotate AWS access keys?

Rotating AWS Access keys is a best practice for managing the security of your AWS accounts. It is a way to periodically update the keys used to access your AWS resources, which helps protect against unauthorised access to your accounts.

There are several reasons why you should rotate your AWS IAM keys:

  1. Security: One of the main reasons to rotate your IAM keys is to enhance the security of your AWS accounts. Regularly updating your keys can minimize the risk of someone gaining unauthorized access to your accounts.

  2. Compliance: Many regulatory standards and industry best practices recommend rotating IAM keys on a regular basis as a way to ensure the security and integrity of your systems.

  3. Convenience: Rotating IAM keys can also be convenient. It allows you to easily revoke access to your resources if a team member leaves your organisation or a key is lost or compromised.

It’s also advised to use IAM roles where possible, but if you have to use access keys, it’s a good idea to rotate them periodically.

How to rotate AWS access keys?

AWS allows an IAM user to have a maximum of 2 access keys. This way, you can rotate your keys without disruption by following the steps below:

  1. Create a new access key.

  2. (Optional) Replace the old access key with the new one everywhere.

  3. Deactivate the old access key.

  4. (Optional) Test the applications using the new key.

  5. Delete the old access key.

The script you will build in this article focuses on replacing all the keys in your credentials file (stored locally on your computer) in one fell swoop. It assumes the keys are only used in your AWS credentials file. Therefore, it skips steps 2 and 4.

Set up the Test Environment

Before getting into the script, create the test environment. It’s always a good idea to test your code first on some dummy accounts.

In the IAM console, click Users and then Add users.

In the user details, enter dummy1 as the user name and click Add another user. Enter dummy2 as the second user name.

Tick Access key - programmatic access in the Select AWS credential type section.

Scroll down to the Attach permissions policies section and click Create policy.

Add user page showing dummy1 and dummy2 users being created and Access key - Programmatic Access is checked as credential type.

Click Next: Permissions.

Click Add users to group (which will make it easier to manage policies attached to the users) and click Create group.

Enter rotate-key-demo as the group name.

Click Create policy (opens a new tab).

At this point, the users you create don’t have any permissions. For a user to be able to reset their own credentials, they need some permissions.

In the Create policy page, switch to the JSON tab and paste the following policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:ListUsers",
                "iam:GetAccountPasswordPolicy"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:*AccessKey*",
                "iam:ChangePassword",
                "iam:GetUser",
                "iam:*ServiceSpecificCredential*",
                "iam:*SigningCertificate*"
            ],
            "Resource": [
                "arn:aws:iam::*:user/${aws:username}"
            ]
        }
    ]
}

This policy allows the user to only reset their own password and access keys.

Click Next:Tags and then Next:Review.

Enter reset-own-credentials as the policy name and click Create policy.

Switch to the group creation tab and click Refresh to see the newly created policy. If it’s not visible on the page, you can search by name to find it.

After you’ve located the policy, tick the checkbox next to it and click the Create group button.

Create group page showing the group name (rotate-key-demo) and policy )reset-own-credentials) selected int he list. Also there is Create group button at the bottom right.

You should now be back on to Add user page. Click the Next:Tags button, then click Next:Review.

Finally, click the Create users button to finalize the process.

After the users have been created, AWS allows you to note down the secret access key. When you close this page, you will not see the secret access key again so copy them and put them in your credentials file.

Add user page after the users have been created. It shows the user names, access key ids and secret access keys (masked)

Update your credentials file with these new accounts:

AWS credentials file showing the newly created users' access key ids and secret access keys

Make sure to keep your actual credentials safe somewhere so that you can put them back in your credentials file.

Now that the test environment is ready let’s start looking into the steps to rotate the AWS access keys.

Implement the script

Create a new PowerShell file, such as rotate-keys.ps1 and paste the following code:

param ([switch]$Remove)

$awsProfiles = Get-AWSCredential -ListProfileDetail
$awsProfiles | %{
  Write-Host "Rotating key for profile [$($_.ProfileName)]" 

  try {
    $newIamAccessKeyResult = New-IAMAccessKey -ProfileName $_.ProfileName
  
    Write-Host "Added new access key: $($newIamAccessKeyResult.AccessKeyId)"
    Set-AWSCredential -AccessKey $newIamAccessKeyResult.AccessKeyId -SecretKey $newIamAccessKeyResult.SecretAccessKey -StoreAs $_.ProfileName

    Write-Host "Waiting 10 seconds for the IAM key to propagate"
    Start-Sleep -Seconds 10 
  
    Write-Host "Getting the oldest key..."
    $oldestKey = Get-IAMAccessKey -ProfileName $_.ProfileName | Sort-Object -Property CreateDate | Select-Object -First 1
    Write-Host "Got the oldest key: $($oldestKey.AccessKeyId)"
    
    if ($Remove) {
      Write-Host "Removing key $($oldestKey.AccessKeyId)"
      Remove-IAMAccessKey -AccessKeyId $oldestKey.AccessKeyId -Force -ProfileName $_.ProfileName
    } else {
      Write-Host "Deactivating key $($oldestKey.AccessKeyId)"
      Update-IAMAccessKey -AccessKeyId $oldestKey.AccessKeyId -Status "Inactive" -Force -ProfileName $_.ProfileName
    }
    
    Write-Host "Access key for [$($_.ProfileName)] has been replaced." 
  } catch {
    Write-Host "An error occured: $PSItem" -ForegroundColor DarkRed 
  }
}

Now, investigate the script line by line:

The script accepts a switch type parameter (like a boolean, it evaluates to true when provided and false otherwise). If you run the script with this argument (e.g. ./rotate-keys.ps1 -Remove), it deletes the old key rather than deactivating it. This is useful when you are sure the keys are not used anywhere and you are confident you can replace the old ones immediately.

The first action is to enumerate all the access keys in your credentials file carried out by the Get-AWSCredential -ListProfileDetail command. If you run this command in a terminal, you should see the following result:

Get-AWSCredential output showing the profilename, storetypename (SharedCredentialsFile) and profile location

It then loops through all the profiles.

First, it creates a new key and updates the credentials file:

$newIamAccessKeyResult = New-IAMAccessKey -ProfileName $_.ProfileName
  
Write-Host "Added new access key: $($newIamAccessKeyResult.AccessKeyId)"
Set-AWSCredential -AccessKey $newIamAccessKeyResult.AccessKeyId -SecretKey $newIamAccessKeyResult.SecretAccessKey -StoreAs $_.ProfileName

In my tests, it takes a few seconds for the new key to propagate, so there is a 10-second delay added to ensure you don’t get an access denied error. You can experiment with this value and see what works best for you.

The next step is to find the oldest key to remove or deactivate. It does this by calling the Get-IAMAccessKey cmdlet. It sorts the results by CreateDate and gets the first result which is the oldest created key.

Then it either removes it completely or deactivates it so that you can undo it easily:

if ($Remove) {
  Write-Host "Removing key $($oldestKey.AccessKeyId)"
  Remove-IAMAccessKey -AccessKeyId $oldestKey.AccessKeyId -Force -ProfileName $_.ProfileName
} else {
  Write-Host "Deactivating key $($oldestKey.AccessKeyId)"
  Update-IAMAccessKey -AccessKeyId $oldestKey.AccessKeyId -Status "Inactive" -Force -ProfileName $_.ProfileName
}

Run the script with the Remove argument, and it should look like this:

Script output showing the access keys have been replaced.

Check the IAM console and make sure the active key matches the one in your credentials file and it’s the newest one.

Now you can replace the dummy keys with your actual ones and rotate them easily by running this script whenever you want.

Conclusion

Dealing with security is always hard. Generally, there is always a security vs convenience trade-off. By automating security-related tasks as much as possible, you can reduce this friction and maintain more secure systems easier. This script and tutorial are just an attempt in this direction. Hope it helps.