MICHAEL WINTERS

Techblah - Using Tailscale with Cognito on your own domain (for free!)


I have been wanting to try Tailscale for a while now, but their somewhat unique decision to require you to host your own OIDC (and deal with security and uptime there … yech) or tie your account to a 3rd party OIDC provider like Github (… yech) presents a real hurdle. I appreciate the security aspects of that decision, and I very much respect their willingness to stick by it. But it still meant that I didn’t get around to trying it for many months.

After the xz security fiasco I decided that I was no longer comfortable with leaving SSH publicly exposed, so it was time to pursue Tailscale in earnest. I didn’t want to spend money on a tech solution that I don’t actually need since I’m my only customer / the only user on my systems, so I was fairly insistent that I would spend zero dollars on this.

In short, the only totally free provider that I could find was Auth0, and their free solution did not include 2FA / one-time passwords (TOTP). To me that represented a downgrade in security which I was uncomfortable with.

But, I was surprised to find that the pricing for AWS Cognito is 100% free if you have < 10,000 users. And while it is technically not a complete OIDC solution, it supports enough of what Tailscale needs, and it has TOTP.

Prereqs

I assume that you have:

If you prefer, I also created a terraform repo for this blog post which will perform steps 1-3 for you. If you use that, then the temporary password will be auto-generated and emailed to you.

1) Create the user pool

If you’ve never worked with identity providers, there’s a lot of lingo involved because these systems are designed to inter-operate in lots of different ways. For our purposes, we need to create a “user pool”, which is like a database that will store all the users of our system.

2) Create your user

3) Enable the OIDC “profile” scope

4) Log into Cognito with your pool user

5) Copy your client secret

6) Create your webfinger

Webfinger is a way for providers like Tailscale to look at your email address (say, [email protected]) and ask the website associated with that email address (example.com) how to find the correct authentication provider for users coming from that domain, e.g. Cognito in our case. It’s a solid security measure for large companies, but it is slightly annoying for us small folk.

In short, Tailscale will do something like curl https://example.com/.well-known/webfinger?resource=acct%3Ajoe%40example.com. You need to respond with some JSON explaining how to authenticate [email protected]. (Note: the mime-type of the response doesn’t matter.)

Now, if you’re like me and hosting a static site, this is a problem, because you have no way to provide a response that is specific to [email protected]. But if you’re also like me and going to be the only user logging into your Tailscale account, you can just hardcode a static response:

{
  "subject": "acct:[email protected]",
  "links": [
    {
      "rel": "http://openid.net/specs/connect/1.0/issuer",
      "href": "paste the login URL from step 4 here"
    }
  ]
}

7) Create your “openid-configuration”

This works just like Step 6 - Tailscale is going to curl https://example.com/.well-known/openid-configuration. However this time it’s not looking for per-user data, so you can actually hardcode this without guilt / tech debt.

The contents of this file are much more verbose, but fortunately you can get this directly from Cognito. You first need to craft a URL that you are going to curl. If you used terraform, this URL is available in the output.

The format for the URL is:

https://cognito-idp.{AWS region of your user pool}.amazonaws.com/{User pool ID}/.well-known/openid-configuration

For example:

https://cognito-idp.us-east-2.amazonaws.com/us-east-2_abcd12345/.well-known/openid-configuration

Fin!

You’re finally ready to sign up for Tailscale! Just select “Sign in with OIDC” and sign up with the email address for your Cognito user. You’ll have to provide the client secret from step 5.

You can also now use Cognito for any other solution that supports OIDC, which is thankfully a growing number of self-hosted tools. And you’re not on the hook for keeping this alive! Just don’t forget about that webfinger tech debt if/when you finally convince your family to use some of the tools you’re running!

Special thanks

When I originally set this up, the OIDC portions of Cognito were totally undocumented. Now they finally have reasonable defaults, but this Stack Overflow was crucial: https://stackoverflow.com/questions/47664727/can-i-use-aws-cognito-to-provide-a-open-id-connect-endpoint

#techblah #selfhosting