# Install an Azure connector on ACI using PowerShell

Azure Container Instances (ACI) is a managed, serverless compute platform for running containerized applications. This guide explains how to install and configure an Apono connector on ACI in your Azure environment using PowerShell.

***

### Prerequisites

<table><thead><tr><th width="249">Item</th><th>Description</th></tr></thead><tbody><tr><td><strong>Apono Token</strong></td><td><p>Account-specific Apono authentication value</p><p>Use the following steps to obtain your token:</p><ol><li>On the <a href="https://app.apono.io/connectors"><strong>Connectors</strong></a> page, click <strong>Install Connector</strong>. The <strong>Install Connector</strong> page appears.</li><li>Click <strong>Cloud installation > Azure > Install and Connect Azure Account > CLI (Container Instance)</strong>.</li><li>Copy the token listed on the page in step <strong>1</strong>.</li></ol></td></tr><tr><td><strong>PowerShell</strong></td><td><a href="https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.4">Tool</a> that enables interacting with Azure services using your command-line shell</td></tr><tr><td><strong>Azure Cloud Information</strong></td><td><p>Information for your Azure Cloud instance:</p><ul><li><a href="https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id">Subscription ID</a></li><li><a href="https://learn.microsoft.com/en-us/azure/governance/management-groups/manage#view-management-groups">Management Group Name</a></li><li><a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal#open-resource-groups">Resource group name</a></li></ul></td></tr><tr><td><strong>Owner Role (Azure RBAC)</strong></td><td><p><a href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner">Azure role</a> with the following permissions:</p><ul><li>Grants full access to manage all resources</li><li>Assigns roles in Azure RBAC</li></ul></td></tr><tr><td><strong>Global Administrator</strong></td><td><p><a href="https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#global-administrator">Microsoft Entra role</a> with the following permission:</p><ul><li>Manages all aspects of Microsoft Entra ID and Microsoft services that use Microsoft Entra identities</li></ul><p>❗<strong>Apono does not require Global Administrator access. This is required for the admin following this guide.</strong> ❗</p></td></tr></tbody></table>

***

### Install a new connector

You can install a connector for an Azure **Management Group** or **Subscription.**

{% hint style="info" %}
The connector requires the following roles:

1. Directory Readers - to validate users in Azure
2. User Access Administrator - to provision and deprovision access in the Management Group

Read more about these Microsoft Entra ID roles [here](https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#directory-readers).
{% endhint %}

{% tabs %}
{% tab title="Management Group" %}
Follow these steps to install a new connector:

1. At the shell prompt, set the environment variables.

```powershell
$env:APONO_CONNECTOR_ID = "<A_UNIQUE_CONNECTOR_NAME>"
$env:APONO_TOKEN = "<APONO_TOKEN>"
$env:SUBSCRIPTION_ID = "<AZURE_SUBSCRIPTION_ID>"
$env:RESOURCE_GROUP_NAME = "<AZURE_RESOURCE_GROUP_NAME>"
$env:MANAGEMENT_GROUP_NAME = "<AZURE_MANAGEMENT_GROUP_NAME>"
```

2. Log in to your Azure account.

```powershell
Connect-AzAccount
```

3. Set the `REGION` environment variable.

{% code overflow="wrap" %}

```powershell
$REGION=$(Get-AzResourceGroup -Name $RESOURCE_GROUP_NAME).Location
```

{% endcode %}

4. Run the following command to deploy the connector on your ACI.

{% code overflow="wrap" %}

```powershell
$port = New-AzContainerInstancePortObject -Port 80 -Protocol TCP

$env_var1 = New-AzContainerInstanceEnvironmentVariableObject -Name "APONO_CONNECTOR_ID" -Value $APONO_CONNECTOR_ID

$env_var2 = New-AzContainerInstanceEnvironmentVariableObject -Name "APONO_TOKEN" -Value $APONO_TOKEN

$env_var3 = New-AzContainerInstanceEnvironmentVariableObject -Name "APONO_URL" -Value "api.apono.io"

$jsonValue = @{
    cloud_provider = "AZURE"
    subscription_id = $SUBSCRIPTION_ID
    resource_group = $RESOURCE_GROUP_NAME
    region = $REGION
    is_azure_admin = $true
} | ConvertTo-Json -Compress

$env_var4 = New-AzContainerInstanceEnvironmentVariableObject -Name "CONNECTOR_METADATA" -Value $jsonValue

$container = New-AzContainerInstanceObject -Image registry.apono.io/apono-connector:v1.7.9 -Name $APONO_CONNECTOR_ID -Port @($port) -EnvironmentVariable @($env_var1, $env_var2, $env_var3, $env_var4) -RequestCpu 1 -RequestMemoryInGb 2 

$imageRegistryCredential = New-AzContainerGroupImageRegistryCredentialObject -Server "registry.apono.io" -Username "apono" -Password (ConvertTo-SecureString $APONO_TOKEN -AsPlainText -Force)

$PRINCIPAL_ID=$(New-AzContainerGroup -SubscriptionId $SUBSCRIPTION_ID -ResourceGroupName $RESOURCE_GROUP_NAME -Name $APONO_CONNECTOR_ID -Container $container -OsType Linux -ImageRegistryCredential $imageRegistryCredential -Location $REGION -IdentityType "SystemAssigned").IdentityPrincipalId
```

{% endcode %}

5. Add the **User Access Administrator** role to the connector in the management group scope.

{% code overflow="wrap" %}

```powershell
New-AzRoleAssignment -ObjectId $PRINCIPAL_ID `
    -ObjectType "ServicePrincipal" `
    -RoleDefinitionName "User Access Administrator" `
    -Scope "/providers/Microsoft.Management/managementGroups/$env:MANAGEMENT_GROUP_NAME"
```

{% endcode %}

6. If your Azure resources have [resource locks](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/lock-resources) applied, assign the **Tag Contributor** role to the connector at the management scope. This allows Apono to add a tag marker during the grant or revoke process.

{% code overflow="wrap" %}

```powershell
New-AzRoleAssignment -ObjectId $PRINCIPAL_ID `
    -ObjectType "ServicePrincipal" `
    -RoleDefinitionName "Tag Contributor" `
    -Scope "/providers/Microsoft.Management/managementGroups/$env:MANAGEMENT_GROUP_NAME"
```

{% endcode %}

7. For Azure AD, add the **Directory Readers** role to the connector. For Azure AD Groups, add the **Groups Administrator** and **Privileged Role Administrator** roles.

{% tabs %}
{% tab title="Azure AD" %}
{% code overflow="wrap" %}

```powershell
$accessToken = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token

$payload = @{
    principalId = $PRINCIPAL_ID
    roleDefinitionId = "88d8e3e3-8f55-4a1e-953a-9b9898b8876b"
    directoryScopeId = "/"
} | ConvertTo-Json -Depth 3

$headers = @{
    "Authorization" = "Bearer $accessToken"
    "Content-Type"  = "application/json"
}

Invoke-RestMethod -Method POST -Uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments" -Headers $headers -Body $payload
```

{% endcode %}
{% endtab %}

{% tab title="Azure AD Groups" %}
{% code overflow="wrap" %}

```powershell
$accessToken = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token

$headers = @{
    "Authorization" = "Bearer $accessToken"
    "Content-Type"  = "application/json"
}

$payload1 = @{
    principalId       = $PRINCIPAL_ID
    roleDefinitionId  = "fdd7a751-b60b-444a-984c-02652fe8fa1c"  # Role ID 1
    directoryScopeId  = "/"
} | ConvertTo-Json -Depth 3

Invoke-RestMethod -Method POST -Uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments" -Headers $headers -Body $payload1

$payload2 = @{
    principalId       = $PRINCIPAL_ID
    roleDefinitionId  = "e8611ab8-c189-46e8-94e1-60213ab1f814"  # Role ID 2
    directoryScopeId  = "/"
} | ConvertTo-Json -Depth 3

Invoke-RestMethod -Method POST -Uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments" -Headers $headers -Body $payload2
```

{% endcode %}
{% endtab %}
{% endtabs %}

8. On the [**Connectors**](https://app.apono.io/connectors) page, verify that the connector has been updated.

You can now integrate with an [Azure Management Group or Azure Subscription](/docs/azure-environment/azure-integrations/integrate-with-azure-management-groups-or-subscriptions.md).
{% endtab %}

{% tab title="Subscription" %}
Follow these steps to install a new connector:

1. At the shell prompt, set the environment variables.

```powershell
$env:APONO_CONNECTOR_ID = "<A_UNIQUE_CONNECTOR_NAME>"
$env:APONO_TOKEN = "<APONO_TOKEN>"
$env:SUBSCRIPTION_ID = "<AZURE_SUBSCRIPTION_ID>"
$env:RESOURCE_GROUP_NAME = "<AZURE_RESOURCE_GROUP_NAME>"
```

2. Log in to your Azure account.

```powershell
Connect-AzAccount
```

3. Set the `REGION` environment variable.

{% code overflow="wrap" %}

```powershell
$env:REGION=$(Get-AzResourceGroup -Name $env:RESOURCE_GROUP_NAME).Location
```

{% endcode %}

4. Run the following command to deploy the connector on your ACI.

{% code overflow="wrap" %}

```powershell
$port = New-AzContainerInstancePortObject -Port 80 -Protocol TCP

$env_var1 = New-AzContainerInstanceEnvironmentVariableObject -Name "APONO_CONNECTOR_ID" -Value $env:APONO_CONNECTOR_ID

$env_var2 = New-AzContainerInstanceEnvironmentVariableObject -Name "APONO_TOKEN" -Value $env:APONO_TOKEN

$env_var3 = New-AzContainerInstanceEnvironmentVariableObject -Name "APONO_URL" -Value "api.apono.io"

$jsonValue = @{
    cloud_provider = "AZURE"
    subscription_id = $env:SUBSCRIPTION_ID
    resource_group = $env:RESOURCE_GROUP_NAME
    region = $env:REGION
    is_azure_admin = $true
} | ConvertTo-Json -Compress

$env_var4 = New-AzContainerInstanceEnvironmentVariableObject -Name "CONNECTOR_METADATA" -Value $jsonValue

$container = New-AzContainerInstanceObject -Image registry.apono.io/apono-connector:v1.7.9 -Name $env:APONO_CONNECTOR_ID -Port @($port) -EnvironmentVariable @($env_var1, $env_var2, $env_var3, $env_var4) -RequestCpu 1 -RequestMemoryInGb 2

$imageRegistryCredential = New-AzContainerGroupImageRegistryCredentialObject -Server "registry.apono.io" -Username "apono" -Password (ConvertTo-SecureString $env:APONO_TOKEN -AsPlainText -Force)

$PRINCIPAL_ID=$(New-AzContainerGroup -SubscriptionId $env:SUBSCRIPTION_ID -ResourceGroupName $env:RESOURCE_GROUP_NAME -Name $env:APONO_CONNECTOR_ID -Container $container -OsType Linux -ImageRegistryCredential $imageRegistryCredential -Location $env:REGION -IdentityType "SystemAssigned").IdentityPrincipalId
```

{% endcode %}

5. Add the **User Access Administrator** role to the connector in the subscription scope.

{% code overflow="wrap" %}

```powershell
New-AzRoleAssignment -ObjectId $PRINCIPAL_ID `
    -ObjectType "ServicePrincipal" `
    -RoleDefinitionName "User Access Administrator" `
    -Scope "/subscriptions/$env:SUBSCRIPTION_ID"
```

{% endcode %}

6. If your Azure resources have [resource locks](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/lock-resources) applied, assign the **Tag Contributor** role to the connector at the subscription scope. This allows Apono to add a tag marker during the grant or revoke process.

```powershell
New-AzRoleAssignment -ObjectId $PRINCIPAL_ID `
    -ObjectType "ServicePrincipal" `
    -RoleDefinitionName "Tag Contributor" `
    -Scope "/subscriptions/$env:SUBSCRIPTION_ID"
```

7. For Azure AD, add the **Director Readers** role to the connector. For Azure AD Groups, add the **Groups Administrator** and **Privileged Role Administrator** roles.

{% tabs %}
{% tab title="Azure AD" %}
{% code overflow="wrap" %}

```powershell
$accessToken = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token

$payload = @{
    principalId = $PRINCIPAL_ID
    roleDefinitionId = "88d8e3e3-8f55-4a1e-953a-9b9898b8876b"
    directoryScopeId = "/"
} | ConvertTo-Json -Depth 3

$headers = @{
    "Authorization" = "Bearer $accessToken"
    "Content-Type"  = "application/json"
}

Invoke-RestMethod -Method POST -Uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments" -Headers $headers -Body $payload
```

{% endcode %}
{% endtab %}

{% tab title="Azure AD Groups" %}
{% code overflow="wrap" %}

```powershell
$accessToken = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token

$headers = @{
    "Authorization" = "Bearer $accessToken"
    "Content-Type"  = "application/json"
}

$payload1 = @{
    principalId       = $PRINCIPAL_ID
    roleDefinitionId  = "fdd7a751-b60b-444a-984c-02652fe8fa1c"  # Role ID 1
    directoryScopeId  = "/"
} | ConvertTo-Json -Depth 3

Invoke-RestMethod -Method POST -Uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments" -Headers $headers -Body $payload1

$payload2 = @{
    principalId       = $PRINCIPAL_ID
    roleDefinitionId  = "e8611ab8-c189-46e8-94e1-60213ab1f814"  # Role ID 2
    directoryScopeId  = "/"
} | ConvertTo-Json -Depth 3

Invoke-RestMethod -Method POST -Uri "https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments" -Headers $headers -Body $payload2
```

{% endcode %}
{% endtab %}
{% endtabs %}

8. On the [**Connectors**](https://app.apono.io/connectors) page, verify that the connector has been updated.

You can now create integrate with an [Azure Management Group or Azure Subscription](/docs/azure-environment/azure-integrations/integrate-with-azure-management-groups-or-subscriptions.md).
{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.apono.io/docs/azure-environment/apono-connector-for-azure/install-azure-connector-on-aci-using-powershell.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
