Published in



I have been working a lot with GitHub recently. It’s a great product, I’m not sure it’s ready for the enterprise yet. However a combination of Azure DevOps and GitHub works a treat. If you are an enterprise that wants to use GitHub, as a secure platform for your internal source code, be sure to look into Enterprise Managed Users. EMU can be enabled on your GitHub Enterprise so your users don’t require a personal GitHub account to connect to your enterprise. I’m not getting into how all that works today. To understand more about EMU you can read this.

This story begins when we tried to use Terraform to manage our GitHub enterprise. Yes there is a Terraform provider for GitHub.

We set up a terraform cloud module to create Groups in Azure Active Directory and another one to create Teams in GitHub. These work great, and once they are linked in GitHub we can just add users to AAD and they will automatically sync into GitHub.

The issue we had comes up when trying to make that link between the GitHub Team to an AAD Group so this sync happens. At first look you might think you would use team-sync API. Which is supported by the Terraform provider here github_team_sync_group_mapping.

However when looking at the GitHub rest API docs for team-sync you will notice this note.

Note: The Team Synchronization API cannot be used with Enterprise Managed Users. To learn more about managing an organization with managed users, see “External groups API”.

OK so lets take a look at the External groups API. Turns out this is the right way to make the link we want. However there is one problem, this API call is not supported in the GitHub Terraform provider as of this writing. Hopefully it will be soon.

In the meantime if you are stuck you can use this script to sync your GitHub team to your IdP Group.

param (
[Parameter(Mandatory=$true)] $team,
[Parameter(Mandatory=$true)] $orgname
# Get all the External IDP groups that can be linked with Teams
$params = @{'Uri' = ('https://api.github.com/orgs/{0}/external-groups' -f $orgname )
'Headers' = @{'Authorization' = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($env:GH_PAT)"))}
'Method' = 'GET'
'ContentType' = 'application/json'}
$externalGroups = Invoke-RestMethod @params
$groups = $externalGroups.groups
foreach ($group in $groups)
$groupName = $group.group_name
# You will need some kind of naming convention between the IdP Group and GH Team so we match with the correct ones
# My terraform module takes one name and creats both so it's easy to match them up.
if ($groupName.Contains($team))
$teamslug = $groupName.ToLower()
$groupId = $group.group_id
$body = @{group_id=$groupId}
$params = @{'Uri' = ('https://api.github.com/orgs/{0}/teams/{1}/external-groups' -f $orgname, $teamslug )
'Headers' = @{'Authorization' = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($env:GH_PAT)"))}
'Method' = 'PATCH'
'ContentType' = 'application/json'
'Body' = ($body | ConvertTo-Json)}
Invoke-RestMethod @params #| ConvertTo-Json



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Dave Lloyd

Dave Lloyd

I have been writing software and teaching/coaching developers for over 35 years. My current passion is Azure DevOps and all the things it can do for a team.