AWS Builder Center
One Login, Two Identities: Putting My Homelab's Authentik in Front of AWS

One Login, Two Identities: Putting My Homelab's Authentik in Front of AWS

How I made a self-hosted identity provider the front door to AWS IAM Identity Center, without renaming myself, creating a second account, or rebuilding a single permission set.

1. Two identity systems that both worked

I had two identity systems, and both of them worked fine on their own.
At home, I run Authentik as the identity provider for my homelab. Every self-hosted service I care about sits behind it, and it lives at auth.homelab.********.nl. In the cloud, I use AWS Organizations with IAM Identity Center. I had a user there, a handful of permission sets, and account assignments that gave me exactly the access I needed across my AWS accounts.
Nothing was broken. But it bothered me that my login journey started in two different places. My homelab had a front door, and AWS had a separate one. I wanted AWS to become just another application behind the identity provider I already run.
There were two catches.
The first: I was not willing to rebuild my AWS setup to get there. My permission sets and account assignments had grown over time, and they were correct. Starting over was not part of the plan.
The second: the two systems didn’t even agree on who I was.
1
2
Authentik private@email.com
AWS IAM Identity Center business@email.com
That left me with the question that shaped this whole project:
Can I log in to AWS with my existing Authentik account, without changing either identity and without touching my AWS permissions?
Spoiler: yes. But the interesting part, as usual, was in the details.

2. Where I started

Before changing anything, it helps to be precise about the starting point.
1
2
3
Homelab
└── Authentik (auth.homelab.*********.nl)
└── user: private@email.com
1
2
3
4
5
AWS Organization
└── IAM Identity Center (identity source: Identity Center directory)
└── user: business@email.com
├── permission sets
└── account assignments
The AWS user was the one that mattered. It was the anchor for every permission set and account assignment I had. Those assignments point at that Identity Center user, not at an email address in some other system.
There were two easy shortcuts, and I didn’t like either of them:
  • Create a new AWS user that matches my Authentik email. That solves the naming problem by moving it to AWS, and then I get to recreate every assignment by hand.
  • Create a second Authentik user just for AWS. That defeats the point of having one identity provider in the first place.
So the goal became very specific: no duplicate Authentik user, no replacement AWS user, no rebuilt assignments. Just a clean, reliable mapping between two identities that already existed.

3. SAML and SCIM solve different problems

When you connect an external identity provider to IAM Identity Center, two acronyms show up together: SAML and SCIM. They are related, but they answer different questions.
SAML: authentication
  • Answers: who is logging in right now, and which existing user are they?
  • Runs: at every login
  • Needed in phase one: yes
SCIM: provisioning
  • Answers: which users and groups should exist in AWS?
  • Runs: in the background, whenever users or groups change
  • Needed in phase one: not yet
My Identity Center user already existed. I didn’t need Authentik to create anything in AWS. I only needed AWS to trust Authentik when I logged in. So phase one was SAML only.
I kept SCIM out on purpose. If I had enabled both and the first login failed, I would have been debugging several layers at once: was Authentik authenticating me, was the assertion right, was AWS matching the right user, or had SCIM just created a second one?
Change one layer, test it, then move on. Provisioning could wait until authentication was boring.

4. The real problem was identity matching

The hard part of this project wasn’t SAML itself. It was figuring out exactly which identifier AWS IAM Identity Center was matching against.
My Authentik account looked like this:
1
2
Username: authentik_username
Email: private@email.com
And my existing IAM Identity Center user looked like this:
1
2
Username: my_aws_username
Email: business@email.com
At first, I focused on the email address.
That turned out to be the wrong field.
During SAML authentication, IAM Identity Center does not match the incoming identity against the user’s email attribute. It matches the SAML NameID against the Identity Center Username.
That distinction became the key to the whole project.
There was one more catch: AWS expects that NameID to use the emailAddress format. So my existing AWS username, my_aws_username, was not a useful federation identifier as-is.
That gave me an awkward combination:
1
2
AWS username:
my_aws_username
1
2
AWS email:
business@email.com
1
2
Authentik email:
private@email.com
I could make Authentik send any of those values, but AWS needed one value that was both suitable as a SAML email-style NameID and exactly equal to the Identity Center username.
In the end, I changed the existing AWS Identity Center username to:
1
business@email.com
I did not create a new user, and I did not rebuild any assignments.
That gave me a stable federation identifier without changing my Authentik account:
The important lesson was not that both systems needed the same email address.
They didn’t.
They only needed one identifier that both sides agreed represented the same user.

5. Preparing AWS without flipping the switch

In the IAM Identity Center console I went to Settings → Identity source → Change identity source and picked External identity provider. The next screen offers AWS’s own service provider metadata: the ACS URL and the issuer URL that the identity provider needs.
I downloaded that metadata file. And then I stopped.
At that moment, the Identity Center directory was still my working login path. The change only takes effect after a final confirmation, and I wanted the Authentik side completely ready before I gave it that confirmation.

6. Creating the AWS application in Authentik

In Authentik, I created a new application called AWS IAM Identity Center.
Instead of manually copying the SAML endpoints from AWS, I used something nicer: AWS lets IAM Identity Center export its Service Provider metadata as XML, and Authentik can import that metadata directly.
So the setup became:
1
2
3
4
5
AWS IAM Identity Center
│
│ SP metadata XML
▼
Authentik SAML provider
The imported metadata filled in the important Service Provider settings for me, including the ACS URL and Audience.
My Authentik application looked roughly like this:
I left the application bindings empty during the initial setup. That kept Authentik-side access control out of the troubleshooting process. Once SAML worked, restricting AWS to a specific Authentik group would be easy enough.
For the protocol settings I used:
1
2
Default NameID Policy:
Email address
1
2
Digest algorithm:
SHA256
1
2
Signature algorithm:
SHA256
1
2
Sign assertions:
Enabled
At that point AWS knew nothing about Authentik yet, but Authentik knew where its assertions had to go.

7. The mapping that makes it work: NameID

This is the part I expected to be difficult, and it ended up being only half of the problem.
I did not want to change my Authentik username or primary email address. Authentik could keep knowing me as:
1
2
username: authentik_username
email: private@email.com
Instead, I added an application-specific attribute to my Authentik user:
Then I created a SAML Provider Property Mapping called AWS NameID.
The final expression I actually used was:
1
2
3
# Customization → Property Mappings → SAML Provider Property Mapping
# Name: AWS NameID
return request.user.attributes.get("aws_username")
I selected that mapping as the SAML provider’s NameID Property Mapping.
Authentik’s built-in preview immediately showed the result:
That gave me the exact assertion value I wanted:
1
2
3
4
<saml:NameID
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">

business@email.com
</saml:NameID>
An important detail: I chose a per-user attribute instead of returning a hard-coded string.
A hard-coded value would work for one person, but every user of the application would then be presented to AWS as the same identity.
With an attribute, each Authentik user can carry their own AWS federation identifier.

8. Closing the loop and flipping the switch

Once Authentik understood AWS, I had to do the reverse.
Authentik exposes its own SAML IdP metadata, including:
1
2
3
EntityID / Issuer
SAML endpoint
Signing certificate
Rather than copying those values manually into AWS, I downloaded Authentik’s metadata file and uploaded it under Identity provider metadata in IAM Identity Center.
That completed the trust in both directions:
1
2
3
AWS metadata
↓
Authentik learns about AWS
1
2
3
Authentik metadata
↓
AWS learns about Authentik
Then came the uncomfortable part: actually changing the Identity Center identity source.
I kept an AWS management session open in another browser while I made the change. That gave me a way back in case the first federated login failed.
Which, as it turned out, was useful.

9. The first login

My first test ended with one of those wonderfully helpful cloud error messages:
Something went wrong
Looks like this code isn’t right. Please try again.
That was all the browser told me.
CloudTrail was more useful.
The failed ExternalIdPDirectoryLogin event contained:
1
Responses must have a name identifier
That sent me back to Authentik.
I checked the SAML provider, the custom NameID mapping, and Authentik’s preview. The preview eventually showed exactly what I expected:
1
2
NameID attribute:
business@email.com
At that point I stopped changing configuration based on guesses.
Instead, I opened Firefox Developer Tools, enabled persistent Network logging, went through the AWS login flow again and captured the actual POST to the IAM Identity Center ACS endpoint.
The POST contained a Base64 encoded SAMLResponse.
After decoding it, I could finally see exactly what AWS was receiving:
1
2
3
4
<saml:NameID
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">

business@email.com
</saml:NameID>
The assertion also had the expected:
1
2
3
4
5
6
Issuer
Audience
Recipient
ACS destination
Signature
InResponseTo
So Authentik was doing its job.
The remaining mismatch was in AWS.
My Identity Center user’s email address was:
1
business@email.com
but its actual username was still:
1
aws_username
That was the moment the whole failure made sense.
AWS was not matching the NameID against the email field I had been looking at. It was matching it against Username.
I updated the existing user’s username to the email-shaped federation identifier:
1
business@email.com
No new Identity Center user. No new permission assignments.
Then I tried again.
This time it worked.

10. What happened to my permission sets?

I opened my normal AWS access portal:
1
https://******.awsapps.com/start
AWS redirected me to Authentik.
I authenticated there as the same homelab user I already used everywhere else.
Authentik returned the SAML assertion.
And instead of an error page, I landed in the AWS access portal.
My existing AWS accounts were still there.
My existing account assignments were still there.
And the entire authentication chain now looked like this:
1
2
3
4
5
6
7
8
9
10
11
12
AWS access portal
↓
Authentik
↓
SAML NameID:
business@email.com
↓
IAM Identity Center
↓
Existing account assignments
↓
AWS accounts
That was the outcome I wanted from the beginning: change who authenticates me without rebuilding how AWS authorizes me.

11. What happened to my permission sets?

Nothing.
And that was the point.
I kept the same Identity Center user. I only changed the identifier used for federation.
The permission sets and account assignments remained attached to that user, so after the first successful Authentik login the same AWS accounts simply appeared in the access portal.
Authentication changed.
Authorization did not.
That distinction is worth remembering:
1
2
Authentik
→ proves who I am
1
2
IAM Identity Center
→ decides which AWS accounts and permission sets I get

12. Lessons learned

  • SAML and SCIM are separate problems.
    I was glad I solved authentication first. Adding provisioning at the same time would have made the debugging surface much larger.
  • The email field is not necessarily the identity AWS matches.
    The most expensive assumption I made was treating the Identity Center email address as the federation identifier. AWS was matching against Username.
  • Inspect the actual SAML assertion.
    Authentik’s preview was useful, but Firefox’s Network inspector ended the guesswork. Once I decoded the actual SAMLResponse, I knew exactly what AWS was receiving.
  • CloudTrail turns vague login errors into useful ones.
    “Looks like this code isn’t right” told me nothing. ExternalIdPDirectoryLogin gave me the first real clue.
  • Application-specific identity attributes are useful.
    My Authentik account did not need to become AWS-shaped. A custom aws_username attribute lets Authentik present the right identifier only when talking to AWS.
  • Existing authorization can survive an authentication migration.
    I changed the login path without rebuilding my AWS account assignments or permission sets.

Conclusion

I started this project because I wanted AWS to become another service behind the identity provider I already run at home.
The end result is almost that simple.
Authentik still knows me as authentik_username, with private@email.com as my normal email address. For AWS, it carries one extra attribute containing the identifier IAM Identity Center expects.
SAML translates between the two.
The part I underestimated was not setting up SAML. It was understanding exactly which identity AWS was trying to match.
Once that became clear, the architecture was straightforward:
1
2
3
4
5
6
7
8
9
Authentik identity
↓
application-specific attribute
↓
SAML NameID
↓
IAM Identity Center username
↓
existing permission sets
No second Authentik account.
No replacement AWS user.
No rebuilt account assignments.
Just one identity provider, one mapping, and the same AWS access I had before.
Authentication is centralized now.
Provisioning is not.
That makes SCIM the obvious next experiment.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article