Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions azure-deploy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# AzureHoundDeploy

## Overview

AzureHound now supports Managed Identity authentication. This allows AzureHound to be run in an Azure Container Instance. The Container Instance must be associated with a Managed Identity that has the required RBAC Roles and Graph Permissions that AzureHound requires.

This repository containes the Azure Resource Manager (ARM) Template along with supporting scripts that
allow a user to conveniently deploy and configure AzureHound to an Azure Container Instance. Specifically this ARM template provides the following functionallity.

1) Deploy an AzureHound Instance that runs in an Azure Container Instance
2) Creates or uses an existing Container Instance
3) Creates or uses an existing Managed Identity for the Container that provides Azure permissions
4) Provides a wizard that configures the AzureHound Instance

## Process


## Prerequisites

In order for this ARM Template to create the container's User Managed Identity, the ARM Template requires an existing User Managed Identity with the following permissions:

- Application.ReadWrite.All
- Managed Identity Contributor
- User Access Administrator

This repository contains a `create-deployment-umi-with-perms.ps1` script that can be used to create deployment's user managed identity. Alternatively you can create the User Managed Identity in the Azure portal.

## AzureHound Required Permissions

AzureHound requires the following Azure permissions

- Directory.Read.All
- Reader

The ARM Template will create the Container Instance along with a User Managed Identity that provides this permissions to the AzureHound Instance.

## Supporting Scripts

The ARM Template is designed to create the Container Instance along with a User Managed Identity that will provide AzureHound with all the permissions it needs to run. However, it

- Create/Fix Managed Identity For The ARM Template
`create-deployment-umi-with-perms.ps1`
- Create/Fix Managed Identity For the Container
`create-container-umi.ps1`
- Full end to end script.
`single-script-full-deployment.ps1`

## Notes About Approach
ManagedIdentities can be assigned permissions just like App Registration (Enterprise Applications), however you are assigning the permissions to
the managed identity's application object id. After creation of a Managed Identity it takes some amount of time before the application id is associated with the managed identity. Therefore we add retry logic.

## Permissions DeploymentScript requires
The `managed-identity-permissions.sh` script will require
the following permissions to be assigned to a managed identity.

# Issues to document

## `single-script-full-deployment`

- it requires tenant-id, but this can be retrieved with `(Get-AzTenant).Id` after logging in with `Connect-AzAccount`
- does it require an existing container registry.
- Maybe use `$registry = New-AzContainerRegistry -ResourceGroupName "myResourceGroup" -Name "mycontainerregistry" -EnableAdminUser -Sku Basic -Location EastUS`
- but permissions required may be a problem.

**maybe create a separate script**

## The docker image must be loaded into the container registry before hand.
To do this this is the following procedure:

1) Have docker installed and running
2) An image registry in Azure must exist or be created
3) Have the authentication information for the existing azure image registry
4) At the command line authenticate with the azure registry
-
5) pull the latest AzureHound image
`docker pull ghcr.io/bloodhoundad/azurehound:<tag>` Note: Use the tag 'latest' unless you want a specific version of azurehound.
6) tag the image to associate it with an the azure registry
`docker tag ghcr.io/owner/repository:tag <AzureRegistryName>.azurecr.io/<AzureRepositoryName>:tag Note: Best to use latest unless you need to maintain multiple versions in Azure's registry.
7) docker push <AzureRegistryName>.azurecr.io/<AzureRepositoryName>:tag




126 changes: 126 additions & 0 deletions azure-deploy/mainTemplate.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// mainTemplate.bicep
targetScope = 'subscription'

@description('Name of the resource group to deploy into')
param resourceGroupName string

@description('Location for all resources')
param location string

@description('Name of the container user managed identity')
param containerUMIName string

@description('Resource group for the container UMI (defaults to main resource group if not specified)')
param containerUMIResourceGroupName string = resourceGroupName

@description('Name of the deployment user managed identity')
param deploymentUMIName string

@description('Resource group containing the deployment user managed identity')
param deploymentUMIResourceGroupName string

@description('Azure tenant ID to analyze')
param azureTenantId string

@description('Bloodhound instance domain')
param bloodhoundInstanceDomain string

@description('Bloodhound token ID')
@secure()
param bloodhoundTokenId string

@description('Bloodhound token')
@secure()
param bloodhoundToken string

var containerName = '${resourceGroupName}-container-group'
var imageName = 'ghcr.io/daviditkin/azurehound:feature-managed-identity-auth-18'

// Create main resource group if it doesn't exist
resource mainRG 'Microsoft.Resources/resourceGroups@2023-07-01' = {
name: resourceGroupName
location: location
}

// Create container UMI resource group if different from main and doesn't exist
resource containerUMIRG 'Microsoft.Resources/resourceGroups@2023-07-01' = if (containerUMIResourceGroupName != resourceGroupName) {
name: containerUMIResourceGroupName
location: location
}

// Get reference to deployment identity
resource deploymentUMI 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
name: deploymentUMIName
scope: resourceGroup(deploymentUMIResourceGroupName)
}

// Deploy or reference the container UMI
module containerIdentity './modules/containerIdentity.bicep' = {
name: 'containerIdentity-deployment'
scope: resourceGroup(containerUMIResourceGroupName)
params: {
location: location
containerUMIName: containerUMIName
}
dependsOn: [
mainRG
containerUMIRG
]
}

// Assign Reader role at subscription scope
resource readerRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().subscriptionId, containerUMIName, 'Reader')
scope: subscription()
properties: {
principalId: containerIdentity.outputs.principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') // Reader role
principalType: 'ServicePrincipal'
}
dependsOn: [
containerIdentity
]
}

// Deploy script to configure Graph API permissions
module graphPermissions './modules/graphPermissions.bicep' = {
name: 'graph-permissions-deployment'
scope: resourceGroup(resourceGroupName) // Changed back to resource group scope since we're deploying a deployment script
params: {
location: location
deploymentUMIId: deploymentUMI.id
deploymentUMIResourceGroupName: deploymentUMIResourceGroupName
deploymentUMIName: deploymentUMIName
containerUMIPrincipalId: containerIdentity.outputs.principalId
}
dependsOn: [
mainRG
containerIdentity
]
}

// Deploy the container instance
module containerInstance './modules/containerInstance.bicep' = {
name: 'container-instance-deployment'
scope: resourceGroup(resourceGroupName)
params: {
location: location
containerGroupName: containerName
containerUMIResourceId: containerIdentity.outputs.resourceId
imageName: imageName
bloodhoundInstanceDomain: bloodhoundInstanceDomain
azureTenantId: azureTenantId
bloodhoundTokenId: bloodhoundTokenId
bloodhoundToken: bloodhoundToken
}
dependsOn: [
mainRG
graphPermissions
]
}

output containerUMIResourceId string = containerIdentity.outputs.resourceId
output containerUMIPrincipalId string = containerIdentity.outputs.principalId
output permissionSetupRequired bool = graphPermissions.outputs.needsManualSetup
output permissionStatus string = graphPermissions.outputs.statusMessage
output assignedPermissions array = graphPermissions.outputs.assignedPermissions
28 changes: 28 additions & 0 deletions azure-deploy/modules/containerIdentity.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// modules/containerIdentity.bicep
param location string
param containerUMIName string

// Reference existing identity if it exists, create if it doesn't
resource containerUMI 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: containerUMIName
location: location
}

// Check if Reader role is already assigned
resource existingReaderRole 'Microsoft.Authorization/roleAssignments@2022-04-01' existing = {
scope: subscription()
name: guid(subscription().id, containerUMI.id, 'Reader')
}

// Assign Reader role at subscription scope if not already assigned
resource readerRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().id, containerUMI.id, 'Reader')
properties: {
principalId: containerUMI.properties.principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') // Reader role
principalType: 'ServicePrincipal'
}
}

output resourceId string = containerUMI.id
output principalId string = containerUMI.properties.principalId
77 changes: 77 additions & 0 deletions azure-deploy/modules/containerInstance.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
param location string
param containerGroupName string
param containerUMIResourceId string
param imageName string
param bloodhoundInstanceDomain string
param azureTenantId string

@secure()
param bloodhoundTokenId string

@secure()
param bloodhoundToken string

var config = {
app: ''
auth: ''
batchsize: 100
config: '/home/nonroot/.config/azurehound/config.json'
instance: 'https://${bloodhoundInstanceDomain}/'
json: false
'managed-identity': true
maxconnsperhost: 20
maxidleconnsperhost: 20
region: 'cloud'
streamcount: 25
tenant: azureTenantId
token: bloodhoundToken
tokenid: bloodhoundTokenId
verbosity: 0
}

resource containerGroup 'Microsoft.ContainerInstance/containerGroups@2023-05-01' = {
name: containerGroupName
location: location
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${containerUMIResourceId}': {}
}
}
properties: {
containers: [
{
name: 'azurehound'
properties: {
image: imageName
command: [
'/azurehound'
'list'
]
volumeMounts: [
{
name: 'config-volume'
mountPath: '/home/nonroot/.config/azurehound'
}
]
resources: {
requests: {
cpu: '1'
memoryInGB: '1'
}
}
}
}
]
volumes: [
{
name: 'config-volume'
secret: {
'config.json': base64(string(config))
}
}
]
osType: 'Linux'
restartPolicy: 'Never'
}
}
Loading