Ben Oram

Quick notes on tech, AWS, .NET & containers

| 1 min read

The dig command is incredibly useful for testing DNS. I use this all the time from Mac and Linux. Windows users, nslookup may provide similar features, but you can always run Linux with WSL

Retrieve nameservers for domain

dig NS

And the address(es) for a particular server


Force the resolution through Google DNS

dig @

Pretent do be from somewhere else

Since Google DNS supports Client Subnet/EDNS we can pretend we are from somewhere else in the world. Let’s try Italy

dig +subnet= @

Reverse DNS

These PTR records don’t always exist, but sometimes provide useful information

> dig -x

Response: ""

mxp64 in the record gives some confirmation that the IPs returned are from CloudFront Milan


| 1 min read

I haven’t had a chance to use Terraform lately, and was pleasantly surprised that you can now specify default tags for nearly all resources at the provider level.

provider "aws" {
    alias = "ohio" 
    region  = "us-east-2"

    default_tags {
        tags = {
            Automation = "Terraform"
            Repo = "Infrastructure.Network"
            Project = "Sandbox"
            Terraform_Workspace = "${var.ATLAS_WORKSPACE_NAME}"            


| 1 min read

AWS Copilot currently doesn’t have support for leveraging docker buildx to allow for multi-architecture docker builds. So the arm64 images created on your M1 Mac with Apple Silicon will not work on AWS Fargate which is based on amd64 today. The error I was seeing in the CloudWatch logs for my load balanced web services was…

standard_init_linux.go:219: exec user process caused: exec format error

As a workaround, specify an arm64 version/tag of your "from" image in your Dockerfile. While this won’t create a multi-architecture image, it will force the creation of an images that will work with AWS Fargate. An example is below for NGINX.

FROM amd64/nginx:alpine
COPY . /usr/share/nginx/html

| 1 min read

I ran into an issue with my EC2 macOS setup where running docker login from SSH resulted in the following error

Error saving credentials: error storing credentials - err: exit status 1, out: `User interaction is not allowed.`

Working around the issue involved running the following in my SSH session before running docker login

security unlock-keychain ${HOME}/Library/Keychains/login.keychain-db 

In subsequent sessions you may see an unknown: Authentication is required error. To avoid, run the unlock-keychain command again.

| 2 min read

I had a chance this week to run macOS on AWS EC2 . First impression, it is expensive and boot/reboot times are very slow. In my case I wanted some dev boxes to hand over to an engineer and I didn’t want to pull out my credit card. I was able to spin up an EC2 instance for each of the 3 most recent versions of MacOS in less than 30 minutes.

If you want to use VNC/Screen Sharing, you will need to run the following two commands to set a password and enable remote management.

# Set pasword
sudo passwd ec2-user

# Enable VNC access
sudo /System/Library/CoreServices/RemoteManagement/ \
-activate -configure -access -on \
-restart -agent -privs -all

# Fixup the disk to make the full EBS volume available
PDISK=$(diskutil list physical external | head -n1 | cut -d" " -f1)
APFSCONT=$(diskutil list physical external | grep "Apple_APFS" | tr -s " " | cut -d" " -f8)
yes | sudo diskutil repairDisk $PDISK

sudo diskutil apfs resizeContainer $APFSCONT 0

Overall MacStadium is much more cost-effective, they know Macs and they have M1. But if you want something running within AWS, your VPC, or in regions where MacStadium doesn’t yet exist and you are ok with Intel, Mac on EC2 works just fine.


| 1 min read

Where possible, leverage the Alpine docker image for ASP.NET Code. Out of the box, the image is more secure than the default Debian buster image, and the Alpine images are a bit smaller.

docker pull

| 1 min read

A nice and simple guide from Ken Disbrow for using Marked 2 as a Markdown preview tool for Drafts

Using Drafts and Marked 2 by Ken Disbrow

| 1 min read

MinVer is a tool that you can use to generate a version number that is based on your git repository history.

The tool does require .NET, but there is no requirement that you develop your app in .NET

Within your GitHub Action workflow, you can run MinVer to generate the version number and store it in an environment variable for later use.

GitHub checkout and set fetch depth appropriately

- uses: actions/checkout@v2
    fetch-depth: 0

Retrieve version and store in env

- name: Set APP_VERSION based on repo w/MinVer
   run: |
    dotnet tool install -g minver-cli -v q
    echo "Adding version to GITHUB_ENV: APP_VERSION=$APP_VERSION"

Example: Reference the variable in later steps

- name: Publish artifact to GitHub
  uses: softprops/action-gh-release@v1
    tag_name: ${{ env.APP_VERSION }}
    GITHUB_TOKEN: ${{ github.token }}


| 1 min read

When launching a Windows instance via an AWS AMI, a password is automatically generated, and encrypted using the keypair associated with the instance.

As a best practice, this generated password should be changed. Many folks choose to create a new local administrator account with a unique username, and additionally many teams choose to join the instance to a domain, and let the domain handle authentication.

Finally, starting with Windows Server 2016, AMIs maintained by AWS are configured to allow generated passwords to expire.


| 1 min read

Storing secrets in source control is something to avoid. Secrets stored in git can easily be inadvertently shared though a fork or push to a public origin, and they are easily found in-bulk by anyone with read access to the repo.

For .NET developers that need secrets on their local machine, leverage dotnet user-secrets to store secrets that can be easily retrieved through configuration. For Mac users, secrets are stored in ~/.microsoft/usersecrets


From your project’s source directory, run this command. It only needs to be run once.

dotnet user-secrets init

Set a secret from command-line/terminal

From your project’s source directory

dotnet user-secrets set "db:password" "VerySecurePassword!0!"

Retrieve secret in code

var password = Configuration["db:password"];


| 1 min read

AWS managed keys are rotated automatically every 3 years. For these keys, there is not a way to manually trigger a key rotation, or change the rotation schedule. These are AWS Managed Keys after all :)

Customer managed keys in KMS have more flexibility. While key rotation is not required, they can be configured automatically rotate every year. In addition, key rotation may be triggered manually, or a rotation can be triggered manually or through API.

To enable manual rotation, make sure that all key references are through an alias. Aliases enable manual key rotation by allowing you to point the alias to a new key at any time.