Maybe you’ve recently deployed CIPP, maybe you’ve been working with it for a while. Either way its good to understand that the core of CIPP is the CIPP-SAM app, this app gets created in your tenant the first time you run through the SAM Wizard.
During the SAM Wizard CIPP will save several details of the app to a Keyvault resource in Azure, details which will be used to authenticate to your customer tenants.
The neat thing is that nothing is stopping you from using those details yourself for your own scripting!
Unlock the door to endless possibilities!
Getting access to Keyvault
First you’ll need to find the keyvault resource CIPP created when it was deployed.
If you were not the person who deployed CIPP you may need to request someone to else to do these actions or to grant you access to the subscription and/or resource group CIPP was deployed in.
The resource will be named something along the line of “cipp
First go to Access Control (IAM). Here you can give yourself or others role based permissions.
In our case we will only need to read secrets so “Key Vault Secrets User” will be perfect.
Second, go to Access policies and create a new Access policy for yourself.
You will only need to add the “GET” and “LIST” secret permissions.
Once you’ve added the permissions you should be able to see the secrets in the Azure UI and request them using the Az.Keyvault module.
Retrieving the secrets from Keyvault
Retrieving the secrets from Keyvault is very simple, you just need to know 3 things.
- The Keyvault name
- The Secret name
- The command to use!
The following is as basic as it gets,
1
$retrievedSecret = Get-AzKeyVaultSecret -VaultName 'mykeyvaultname' -Name 'secretname' -AsPlainText -ErrorAction Stop
If you need to request multiple secrets and save them to variables, you can for example use this little snippet.
It will retrieve them and store them in variables that are named the same as the secrets themselves.
1
2
3
@('ApplicationId','ApplicationSecret','RefreshToken', 'tenantid') | Foreach-Object {
New-Variable -Name $_ -Value (Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $_ -AsPlainText -ErrorAction Stop) -Force
}
Using the secrets to authenticate
For demonstration purposes I will be using my own function here, but there are an endless number of ways to Rome.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
function Get-MicrosoftToken {
Param(
# Tenant Id
[Parameter(Mandatory=$false)]
[guid]$TenantId,
# Scope
[Parameter(Mandatory=$false)]
[string]$Scope = 'https://graph.microsoft.com/.default',
# ApplicationID
[Parameter(Mandatory=$true)]
[guid]$ApplicationID,
# ApplicationSecret
[Parameter(Mandatory=$true)]
[string]$ApplicationSecret,
# RefreshToken
[Parameter(Mandatory=$true)]
[string]$RefreshToken
)
if ($TenantId) {
$Uri = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token"
}
else {
$Uri = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
}
# Define the parameters for the token request
$Body = @{
client_id = $ApplicationID
client_secret = $ApplicationSecret
scope = $Scope
refresh_token = $RefreshToken
grant_type = 'refresh_token'
}
$Params = @{
Uri = $Uri
Method = 'POST'
Body = $Body
ContentType = 'application/x-www-form-urlencoded'
UseBasicParsing = $true
}
try {
$AuthResponse = (Invoke-WebRequest @Params).Content | ConvertFrom-Json
} catch {
throw "Authentication Error Occured $_"
}
return $AuthResponse
}
try {
$customertenantId = 'customertenantidhere'
$keyVaultName = 'yourkeyvaultnamehere'
# Our secrets from the CIPP Keyvault
@('ApplicationId','ApplicationSecret','RefreshToken', 'tenantid') | Foreach-Object {
New-Variable -Name $_ -Value (Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $_ -AsPlainText -ErrorAction Stop) -Force
}
# To keep the code clean we'll define some of the secrets in a splat
$commonTokenSplat = @{
ApplicationID = $ApplicationId
ApplicationSecret = $ApplicationSecret
RefreshToken = $RefreshToken
}
# Here we're requesting a Graph token for $customertenantId
if ($token = (Get-MicrosoftToken @commonTokenSplat -TenantID $customertenantid -Scope "https://graph.microsoft.com/.default").Access_Token) {
$header = @{
Authorization = 'bearer {0}' -f $token
Accept = "application/json"
}
}
} catch {
throw "Auth failed: $($_.Exception.Message)"
}
$header should now contain a valid graph token for $tenant and alllow you to make a call like
1
Invoke-RestMethod -Method GET -Uri 'https://graph.microsoft.com/beta/organization' -Headers $header
We are of course not limited to Graph API, you can also use the secrets and the CIPP-SAM app to request tokens for Exchang Online, Sharepoint, Teams, Partner Center and other Microsoft services.
Needless to say, these secrets should be treated like nuclear secrets. They will give unattended access to all of your customer tenants, if a malicious actor manages to get a hold of them your company is likely bankrupt.
Happy scripting!