Changing IDP in self hosted NB

Has anyone tried / had luck in changing the IDP in their self hosted instance? I’m planning on moving from Google workspace to M365 and that will bring in the change from Google SSO to Entra ID. What’s the best strategy here to preserve my current config?
Solution:
Probably obvious, but just changing the IDP does not work lol. But had to see for myself. I created an instance with Zitadel, setup a few things. Then reconfigured the compose file and config files to accept authentik as the IDP with the same NetBird DB. No dice lol. But had to see for myself. I’ve now settled on starting over a new instance with Zitadel and will continually add IDPs as required...
Jump to solution
23 Replies
Codixer
Codixer2mo ago
oh god, that's a good one. Depends on how the SSO is configured. Since the IDP contains the unique ID used to authenticate. My best estimate to what you can do... I have no idea. Not only moving the users, but also all devices? Christ, that's gonna be hell. Most people have something like Authentik or Keycloak in front of their instance and handle logging into netbird from there, while logging in with M365 or Google as a social option.
AYEEDITYA
AYEEDITYAOP2mo ago
I’ve got this thought as well and I’m now regretting not just integrating with Zitadel from the get go. Maybe I’ll just bite the bullet and start clean
Codixer
Codixer2mo ago
how many agents did you have
AYEEDITYA
AYEEDITYAOP2mo ago
I’ve got around 50 daily peers right now
Codixer
Codixer2mo ago
heh Dear god Good luck
AYEEDITYA
AYEEDITYAOP2mo ago
lol thank you! I spoke with my IT guys and they’ve suggested just going with Zitadel now. Basically to redo NB with Zitadel + Google. Then add Microsoft SSO to Zitadel. I think this way we can maintain the users
Codixer
Codixer2mo ago
I think or feel Zitadel is a bit limiting, but that could just be my opinion. Authentik has been my go-to Since it allows you to customize each process
AYEEDITYA
AYEEDITYAOP2mo ago
Hmm does authentic allow multiple IDPs?
Codixer
Codixer2mo ago
Yes
AYEEDITYA
AYEEDITYAOP2mo ago
Will have to read up about authentik.
What do you feel is missing in Zitadel?
Codixer
Codixer2mo ago
No description
Codixer
Codixer2mo ago
No description
Codixer
Codixer2mo ago
No description
Codixer
Codixer2mo ago
Customization
No description
Codixer
Codixer2mo ago
I can make authentik run python code based on the stuff that I need from it, so lets say you auth with Discord, I can validate your servers and the roles you have within them and check what groups in AUthentik you need access to.
No description
AYEEDITYA
AYEEDITYAOP2mo ago
Okay! I will take a couple days and read up on authentik. Thank you for the tip! I’ve actually got Zitadel running right now. But it’s not actively being utilized. So switch to something else isn’t too hard
Codixer
Codixer2mo ago
from authentik.core.models import Group
GUILD_API_URL = "https://discord.com/api/users/@me/guilds/{guild_id}/member"

### CONFIG ###
guild_id = "1033768436960075796"
##############

# Ensure flow is only run during OAuth logins via Discord
if context["source"].provider_type != "discord":
return True

# Get the user-source connection object from the context, and get the access token
connection = context.get("goauthentik.io/sources/connection")
if not connection:
return False
access_token = connection.access_token

guild_member_request = requests.get(
GUILD_API_URL.format(guild_id=guild_id),
headers={
"Authorization": f"Bearer {access_token}"
},
)
guild_member_info = guild_member_request.json()

# Ensure we are not being ratelimited
if guild_member_request.status_code == 429:
ak_message(f"Discord is throttling this connection. Retry in {int(guild_member_info['retry_after'])}s")
return False

# Ensure user is a member of the guild
if "code" in guild_member_info:
if guild_member_info["code"] == 10004:
ak_message("You are not a member of the <REDACTED> Discord. Please request access.")
else:
ak_create_event("discord_error", source=context["source"], code=guild_member_info["code"])
ak_message("Discord API error, try again later.")
return False

# Get all discord_groups
discord_groups = Group.objects.filter(attributes__discord_role_id__isnull=False)

# Split user groups into discord groups and non discord groups
user_groups_non_discord = request.user.ak_groups.exclude(pk__in=discord_groups.values_list("pk", flat=True))
user_groups_discord = list(request.user.ak_groups.filter(pk__in=discord_groups.values_list("pk", flat=True)))

# Filter matching roles based on guild_member_info['roles']
user_groups_discord_updated = discord_groups.filter(attributes__discord_role_id__in=guild_member_info["roles"])

# Combine user_groups_non_discord and matching_roles
user_groups_updated = user_groups_non_discord.union(user_groups_discord_updated)

# Update user's groups
request.user.ak_groups.set(user_groups_updated)

# Create event with roles changed
ak_create_event(
"discord_role_sync",
user_discord_roles_before=", ".join(str(group) for group in user_groups_discord),
user_discord_roles_after=", ".join(str(group) for group in user_groups_discord_updated),
)

return True
from authentik.core.models import Group
GUILD_API_URL = "https://discord.com/api/users/@me/guilds/{guild_id}/member"

### CONFIG ###
guild_id = "1033768436960075796"
##############

# Ensure flow is only run during OAuth logins via Discord
if context["source"].provider_type != "discord":
return True

# Get the user-source connection object from the context, and get the access token
connection = context.get("goauthentik.io/sources/connection")
if not connection:
return False
access_token = connection.access_token

guild_member_request = requests.get(
GUILD_API_URL.format(guild_id=guild_id),
headers={
"Authorization": f"Bearer {access_token}"
},
)
guild_member_info = guild_member_request.json()

# Ensure we are not being ratelimited
if guild_member_request.status_code == 429:
ak_message(f"Discord is throttling this connection. Retry in {int(guild_member_info['retry_after'])}s")
return False

# Ensure user is a member of the guild
if "code" in guild_member_info:
if guild_member_info["code"] == 10004:
ak_message("You are not a member of the <REDACTED> Discord. Please request access.")
else:
ak_create_event("discord_error", source=context["source"], code=guild_member_info["code"])
ak_message("Discord API error, try again later.")
return False

# Get all discord_groups
discord_groups = Group.objects.filter(attributes__discord_role_id__isnull=False)

# Split user groups into discord groups and non discord groups
user_groups_non_discord = request.user.ak_groups.exclude(pk__in=discord_groups.values_list("pk", flat=True))
user_groups_discord = list(request.user.ak_groups.filter(pk__in=discord_groups.values_list("pk", flat=True)))

# Filter matching roles based on guild_member_info['roles']
user_groups_discord_updated = discord_groups.filter(attributes__discord_role_id__in=guild_member_info["roles"])

# Combine user_groups_non_discord and matching_roles
user_groups_updated = user_groups_non_discord.union(user_groups_discord_updated)

# Update user's groups
request.user.ak_groups.set(user_groups_updated)

# Create event with roles changed
ak_create_event(
"discord_role_sync",
user_discord_roles_before=", ".join(str(group) for group in user_groups_discord),
user_discord_roles_after=", ".join(str(group) for group in user_groups_discord_updated),
)

return True
AYEEDITYA
AYEEDITYAOP2mo ago
Woah that’s pretty cool! Are you using authentik for home labbing? Or in an enterprise environment?
Codixer
Codixer2mo ago
Both
Codixer
Codixer2mo ago
Currently about 30 or so users
No description
Codixer
Codixer2mo ago
With a total of 47 peers
No description
AYEEDITYA
AYEEDITYAOP2mo ago
Nice! Would it be okay if I reach out in the future if I need any help?
Solution
AYEEDITYA
AYEEDITYA2mo ago
Probably obvious, but just changing the IDP does not work lol. But had to see for myself. I created an instance with Zitadel, setup a few things. Then reconfigured the compose file and config files to accept authentik as the IDP with the same NetBird DB. No dice lol. But had to see for myself. I’ve now settled on starting over a new instance with Zitadel and will continually add IDPs as required

Did you find this page helpful?