> For the complete documentation index, see [llms.txt](https://docs.bluerock.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bluerock.io/deployment-guides/azure-deployments/azure-deployment-with-cli.md).

# Azure Deployment with CLI

This guide provides the necessary technical steps to install the Microsoft Azure CLI, configure your project environment, and deploy BlueRock-hardened instances on Microsoft Azure.

### Prerequisites

* Microsoft Azure CLI tools (`az`), for installation, refer to the official [Microsoft Azure CLI installation guide](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest).
* BlueRock images: BlueRock provides pre-packaged images of BlueRock Ubuntu 2404 Linux Distribution. Contact [BlueRock support](https://www.bluerock.io/contact) for the images.

| OS           | Kernel Version | Image Name                                                 | Description                                                                                             |
| ------------ | -------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Ubuntu 24.04 | 6.12.89        | bluerock-release-26-23-1-ubuntu2404-6-12-89-20260724125938 | Provides full policy configuration control. Allow switching policy action from observe to enforce mode. |

### Procedure

To deploy the BlueRock-hardened instances on Microsoft Azure with the CLI, the following is the procedure:

1. [Instance Deployment](#instance-deployment)
2. [Create Storage Container](#create-a-storage-container)
3. [Instance Configuration](#bluerock-instance-configuration)
4. [Updating Configuration Source](#updating-configuration-source)
5. [OTEL Event Collection](#otel-event-collection-setup)
6. [View Logs in Azure](#view-logs-in-azure)
7. [Configuring Remote Project Workspace in Claude Desktop IDE](#configuring-remote-project-workspace-in-claude-desktop-ide)

### Instance Deployment

To deploy a BlueRock VM in a Customer (Target) Azure Account using the Golden Image hosted in the BlueRock Production Account, cross-tenant authentication must be established. A Service Principal authorized in both the source and target tenants is required to facilitate this deployment.

Execute the following Azure CLI script to authenticate the Service Principal across both tenants, generate the User Assigned Managed Identity, and provision the virtual machine. Modify the variables at the top of the script to match the target environment details:

{% code overflow="wrap" %}

```shellscript
# Define environment variables
$ tenant1="<Tenant-ID-of-BlueRock-Prod>"
$ tenant2="<Tenant-ID-of-Customer>"
$ appid="<BlueRock-Image-Share-AppID>"
$ secret="<BlueRock-Image-Share-App-Secret>"
$ image_id="<BlueRock-Ubuntu-Golden-Image-ID>"
$ rg_name="<Customer-Resource-Group-Name>"
$ uami_name="<Managed-Identity-Name>"
$ location="<Azure-Region-e.g.-eastus>"
$ ssh_pubkey_path="<path-to-ssh-pubkey>"

# Authenticate against the BlueRock Production tenant
$ az login --service-principal -u "${appid}" -p "${secret}" --tenant "${tenant1}"
$ az account get-access-token

# Authenticate against the Customer target tenant
$ az login --service-principal -u "${appid}" -p "${secret}" --tenant "${tenant2}"
$ az account get-access-token 

# Create Managed Identity
$ az identity create --resource-group "${rg_name}" --name "${uami_name}" --location "${location}"
$ uami_id=$(az identity show --resource-group "${rg_name}" --name "${uami_name}" --query id -o tsv)

# Provision the BlueRock VM in the target environment
$ az vm create \
  --resource-group "${rg_name}" \
  --name bluerock-ubuntu-vm \
  --image "${image_id}" \
  --admin-username ubuntu \
  --ssh-key-values @"${ssh_pubkey_path}" \
  --size Standard_D2s_v3 \
  --assign-identity "${uami_id}"
```

{% endcode %}

`az vm create` parameters table:

<table data-header-hidden data-search="false"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><strong>Parameter</strong></td><td><strong>Description</strong></td><td><strong>Value in Your Command</strong></td></tr><tr><td><code>--resource-group</code></td><td>The logical container in Azure where the VM and its associated resources (disk, network, etc.) will be stored.</td><td><code>&#x3C;resource-group-name></code></td></tr><tr><td><code>--name</code></td><td>The unique name assigned to your virtual machine within the resource group.</td><td><code>bluerock-ubuntu-vm</code></td></tr><tr><td><code>--image</code></td><td><p>The Operating System image to install. In this case, you're using a variable (<code>$image_id</code>) which likely points to the BlueRock Node AMI.</p><p><a class="button secondary"></a></p></td><td><code>$image_id</code></td></tr><tr><td><code>--admin-username</code></td><td>The name of the primary administrator account created on the VM.</td><td><code>ubuntu</code></td></tr><tr><td><code>--ssh-key-values</code></td><td>The path to your SSH public key for secure, passwordless authentication. The <code>@</code> symbol tells the CLI to read the content of the file at that path.</td><td><code>@&#x3C;path-to-ssh-pubkey></code></td></tr><tr><td><code>--size</code></td><td>The hardware profile (SKU) of the VM. <code>Standard_D2s_v3</code> provides a balanced 2 vCPUs and 8 GiB of memory.</td><td><code>Standard_D2s_v3</code></td></tr><tr><td><code>--location</code></td><td>The Azure region (datacenter) where the VM will be physically hosted.</td><td><code>eastus</code></td></tr><tr><td><code>--assign-identity</code></td><td>Associates a Managed Identity (such as a User-Assigned Managed Identity) with the virtual machine to allow secure, credential-free access to other Azure resources.</td><td><code>$uami_id</code></td></tr></tbody></table>

The required variable values are sourced from a combination of the BlueRock administrative team and the target Customer's Azure environment.

Below is a breakdown of where each specific value is retrieved:

<table data-header-hidden data-search="false"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Variable</strong></td><td><strong>Description &#x26; Source</strong></td></tr><tr><td><code>tenant1</code></td><td>BlueRock Production Tenant ID: Provided directly by BlueRock support.</td></tr><tr><td><code>tenant2</code></td><td>Customer Tenant ID: Retrieved from the Customer's Azure environment. In the Azure Portal, navigate to Microsoft Entra ID > Overview. The value is listed as the Tenant ID.</td></tr><tr><td><code>appid</code></td><td>Service Principal App ID: Provided by BlueRock support. This is the Application (client) ID of the Service Principal explicitly authorized to access the shared Golden Image.</td></tr><tr><td><code>secret</code></td><td>Service Principal Secret: Provided securely by BlueRock support. This acts as the authentication password for the Service Principal.</td></tr><tr><td><code>image_id</code></td><td>Golden Image Resource ID: Provided by BlueRock support. This is the full Azure Resource Manager (ARM) path to the specific BlueRock Ubuntu image (e.g., <code>/subscriptions/.../resourceGroups/.../providers/Microsoft.Compute/images/...</code>).</td></tr><tr><td><code>rg_name</code></td><td>Customer Resource Group Name: The existing resource group in the Customer's Azure environment where the VM and Managed Identity will be provisioned.</td></tr><tr><td><code>uami_name</code></td><td>Managed Identity Name: The desired name for the User Assigned Managed Identity (UAMI) created during the deployment.</td></tr><tr><td><code>location</code></td><td>Azure Region: The specific Azure data center location where the resources will be deployed (e.g., <code>eastus</code>, <code>westeurope</code>).</td></tr><tr><td><code>ssh_pubkey_path</code></td><td>SSH Public Key Path: The local file path to the SSH public key used for authenticating into the deployed VM (e.g., <code>~/.ssh/id_ed25519.pub</code>).</td></tr></tbody></table>

To validate the instance status:

```shellscript
$ az vm show --resource-group <your-resource-group> --name <instance-name> --show-details --query "powerState" --output tsv
```

To connect with instance using SSH:

```shellscript
$ ssh -i <path-to-priv-key> ubuntu@<ssh-ip-address>
```

{% hint style="info" icon="notes-sticky" %}
**Note:**\
SSH may give some warnings and prompts to generate an SSH key for the first time. While generating an SSH key leave the passphrase as empty by pressing Enter. It will automatically create the key and add the key permanently to the host.&#x20;
{% endhint %}

### Create a Storage Container

Ensure to create an Azure Storage Container to save the Configuration file and Policy files as the BlueRock Instance picks these files from a separate container using config.source file that contains this Blob's URL/URI.

Create Storage Account:

```shellscript
$ az storage account create \
  --name <storageaccountname> \
  --resource-group <your-resource-group> \
  --location eastus \
  --sku Standard_LRS
```

Create Storage Container:

```shellscript
$ az storage container create \
  --name <your-container-name> \
  --account-name <storageaccountname> \
  --auth-mode login
```

#### Identify the Managed Identity

Authentication for a BlueRock instance without managed keys requires a Managed Identity, either System-assigned or User-defined. The following command retrieves the Principal ID (Object ID) of the managed identity used while creating the VM instance.

Get the Object ID (Principal ID):

```shellscript
$ az identity show \
  --resource-group "my_resource_group" \
  --name "managed_identity_name" \
  --query principalId -o tsv
```

#### Authorize the BlueRock Instance (RBAC)

Granting the **Storage Blob Data Contributor** role to the identified **Object ID** ensures the instance possesses authority to download policy and configuration artifacts during the startup verification process. UC performs policy signature verification during startup before loading the configuration.

Create the Role Assignment:

```shellscript
$ az role assignment create \
  --assignee-object-id "object_id_from_previous_step" \
  --assignee-principal-type ServicePrincipal \
  --role "Storage Blob Data Contributor" \
  --scope "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>"
```

### BlueRock Instance Configuration

BlueRock instances have a configuration file `bluerockd.toml` to define telemetry and policy settings that resides at `/etc/bluerock/`.&#x20;

{% code title="bluerockd.toml" overflow="wrap" lineNumbers="true" %}

```toml
[runtime]
metrics_timer = 1800
state_dir = "/var/lib/bluerockd/"
[policy]
public_key = "az://{{STORAGE_ACCOUNT}}/{{BLOB_CONTAINER}}/{{PUBKEY_FILE}}"
poll_period = 300
[policy.source]
location   = "az://{{STORAGE_ACCOUNT}}/{{BLOB_CONTAINER}}/"
policy     = "policy.json"
policy_sig = "policy.json.sig"
[policy.source.transport]
auth_method = "managed_identity"
[otlp]
file = "/var/log/bluerockd/otel-events.log"
[otlp.http]
url = "http://<internal_ip>:4318/"
```

{% endcode %}

<table data-header-hidden data-search="false"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><strong>Parameter</strong></td><td><strong>Type</strong></td><td><strong>Description</strong></td></tr><tr><td><code>metrics_timer</code></td><td>Integer</td><td>How often (in seconds) the agent pushes its performance metrics (e.g., <code>1800</code> = 30 minutes).</td></tr><tr><td><code>state_dir</code></td><td>Path / String</td><td>The local directory path where the agent (<code>bluerockd</code>) stores its internal state data.</td></tr><tr><td><code>policy.public_key</code></td><td>Azure Blob Path</td><td>The Azure Blob Storage URL path to the public key used to validate the policy signature file (<code>az://</code> protocol).</td></tr><tr><td><code>policy.poll_period</code></td><td>Integer</td><td>How often (in seconds) the agent checks Azure Blob Storage for a new policy version (e.g., <code>300</code> = 5 minutes).</td></tr><tr><td><code>policy.source.location</code></td><td>Azure Blob Path</td><td>The base Azure Blob Storage container path where the policy-related files are stored.</td></tr><tr><td><code>policy.source.policy</code></td><td>File Name</td><td>The specific JSON file name containing the configuration rules.</td></tr><tr><td><code>policy.source.policy_sig</code></td><td>File Name</td><td>The digital signature file used to verify that the <code>policy.json</code> hasn't been tampered with.</td></tr><tr><td><code>policy.source.transport.auth_method</code></td><td>String</td><td>Authentication type. Setting it to <code>managed_identity</code> uses the Azure Managed Identity assigned to the host machine/resource.</td></tr><tr><td><code>otlp.file</code></td><td>Path / String</td><td>The local file path where OpenTelemetry log events are written.</td></tr><tr><td><code>otlp.http.url</code></td><td>URL</td><td>The local or internal HTTP endpoint (usually an OTLP/HTTP receiver or collector) where telemetry data is forwarded.</td></tr></tbody></table>

{% hint style="info" icon="notes-sticky" %}
**Note:**&#x20;

BlueRock Secure MCP Server enforces runtime security controls through configurable MCP Protection Policies. Refer to the [Policy Configuration guide ](/policy-configuration/policy-life-cycle.md#policy-source-configuration)to learn more about these policies.
{% endhint %}

After editing the `bluerockd.toml`  restart the `bluerockd.service` .

```shellscript
$ sudo systemctl restart bluerockd.service
```

#### BlueRock Custom Policy Configuration

The Full Edition facilitates custom policy enforcement via the TREX tool. This workflow includes environment activation, template generation, cryptographic signing, and artifact upload.

1. Navigate to the TREX directory

   ```shellscript
   $ cd /opt/bluerock/trex
   ```
2. Create signing key or certificate

   ```shellscript
   openssl req -x509 -newkey rsa:4096 -keyout dynpol_key.pem -out dynpol_cert.pem -sha256 -days 3650 -nodes -subj "/C=XX/ST=StateName/L=CityName/O=CompanyName/OU=CompanySectionName/CN=CommonNameOrHostname"
   ```
3. Extract pub key from certificate

   ```shellscript
   $ openssl x509 -pubkey -noout -in dynpol_cert.pem  > dynpol_pubkey.pem
   ```
4. Create the `trex.toml`&#x20;

   <pre class="language-toml" data-title="trex.toml" data-overflow="wrap" data-line-numbers><code class="lang-toml">[incoming]
   sig_required = false
   sig_hash = "sha256"
   public_key_pem = "dynpol_cert.pem"
   [outgoing]
   sig_required = true 
   sig_hash = "sha256"
   private_key_pem = "dynpol_key.pem"
   private_key_passphrase = ""
   </code></pre>
5. Activate TREX Environment

   ```shellscript
   $ source /opt/bluerock/trex/py312/bin/activate
   ```
6. Generate Policy Template

   ```shellscript
   $ cp bru_policy.json.template bru_policy.json
   ```

   Manual editing of the JSON file allows defining specific rules, such as enabling or disabling MCP remediation.
7. Generate Signed Policy Blob\
   The TREX tool processes the JSON file to generate a signed policy package in `.tar` format:

   ```shellscript
   $ python trex.py bru_policy.json
   ```
8. Extract Policy Artifacts\
   Extraction of the signed blob archive yields the specific files necessary for UC verification:

   ```shellscript
   $ tar xvf bru_policy.tar
   ```
9. Set environment variables

   ```shellscript
   $ export AZCOPY_AUTO_LOGIN_TYPE=MSI 
   $ export AZCOPY_MSI_CLIENT_ID=<client_ID>
   ```
10. Upload BlueRock configuration

    <pre class="language-shellscript" data-overflow="wrap"><code class="lang-shellscript">$ azcopy copy policy.json https://&#x3C;url>.blob.core.windows.net/pol/policy.json
    $ azcopy copy policy.json.sig https://&#x3C;url>.blob.core.windows.net/pol/policy.json.sig
    </code></pre>

{% hint style="info" icon="notes-sticky" %}
**Note:**

Upload only the public key for the digital signature so that the signed policy blob (`policy.json`) can be verified by the system using that key.
{% endhint %}

***

### OTEL Event Collection Setup

To forward OpenTelemetry (OTEL) events and agent telemetry, an Azure Log Analytics Workspace and an Application Insights component must be created and linked.

1. Create Azure Monitoring Resources\
   Use the Azure CLI to provision the workspace, create the Application Insights component, and retrieve the required connection string:

   <pre class="language-shellscript" data-overflow="wrap"><code class="lang-shellscript"># Create the Log Analytics Workspace with a 30-day retention policy
   $ az monitor log-analytics workspace create \
     --resource-group &#x3C;rg-name> \
     --workspace-name &#x3C;workspace-name> \
     --retention-time 30

   # Create the workspace-based Application Insights component
   $ az monitor app-insights component create \
     --app &#x3C;app-name> \
     --location &#x3C;region-name> \
     --resource-group &#x3C;rg-name> \
     --workspace &#x3C;workspace-resource-id>

   # Retrieve the connection string required for the OTEL collector
   $ az monitor app-insights component show \
     --app &#x3C;app-name> \
     --resource-group &#x3C;rg-name> \
     --query connectionString -o tsv
   </code></pre>
2. Locate the OTEL config file:

   ```shellscript
   $ cd /opt/bluerock/otel

   $ ls

   otel-config.yaml
   ```
3. Edit the `otel-config.yaml` file based on the requirements.
4. Enable the otel service

   ```shellscript
   $ sudo systemctl enable otelcol.service
   ```
5. Start the otel service

   ```shellscript
   $ sudo systemctl start otelcol.service
   ```
6. Check the status of the otel service

   ```shell
   $ sudo systemctl status otelcol.service --no-pager -l
   ● otelcol.service - OpenTelemetry Collector (Bluerock)
        Loaded: loaded (/etc/systemd/system/otelcol.service; enabled; preset: enabled)
        Active: active (running) since Fri 2026-07-03 03:15:22 UTC; 7h ago
          Docs: https://opentelemetry.io/docs/collector/
      Main PID: 3227 (aws-otel-collec)
         Tasks: 9 (limit: 18800)
        Memory: 19.9M (peak: 21.7M)
           CPU: 19.917s
        CGroup: /system.slice/otelcol.service
                └─3227 /opt/azure/aws-otel-collector/bin/azure-otel-collector --config=/opt/bluerock/otel/otel-config.yaml
   Jul 03 03:15:22 ip-172-31-29-175 run-otelcol.sh[3227]: 2026-07-03T03:15:22.324Z        debug        builders/builders.go:24        Stable component.        {"resource": {"service.instance.id": "27df2ba6-b766-4dc7-9b5b-c80a5956c45c", "service.name": "aws-otel-collector", "service.version": "v0.44.0"}, "otelcol.component.id": "otlp", "otelcol.component.kind": "receiver", "otelcol.signal": "logs"}
   Jul 03 03:15:22 ip-172-31-29-175 run-otelcol.sh[3227]: 2026-07-03T03:15:22.324Z        debug        Logger core does not support injecting component attributes        {"resource": {"service.instance.id": "27df2ba6-b766-4dc7-9b5b-c80a5956c45c", "service.name": "aws-otel-collector", "service.version": "v0.44.0"}, "otelcol.component.id": "otlp", "otelcol.component.kind": "receiver", "otelcol.signal": "logs"}
   ```

### View Logs in Azure

Events generated by the BlueRock instance are forwarded to the **Azure Log Analytics Workspace** and can be queried using Kusto Query Language (KQL).

Navigate to **Azure Log Analytics Workspace** > select an instance name > **Logs**. In the logs workspace change the **Simple mode** to **KQL mode** run the required query to view application traces.&#x20;

<figure><img src="/files/iBMnkSQHEhUldFnnxb3V" alt=""><figcaption></figcaption></figure>

Following is a sample KQL query:

```shellscript
// Retrieve the 50 most recent application traces from the last 10 minutes
AppTraces
| where TimeGenerated > ago(10m)
| project TimeGenerated, Message, SeverityLevel, Properties
| order by TimeGenerated desc
| take 50
```

### Configuring Remote Project Workspace in Claude Desktop IDE

To allow AI-assisted development while maintaining BlueRock's telemetry tracking, a dedicated user session must be established for the Claude Desktop IDE.

1. Create the User Account and Configure SSH:\
   Connect to the BlueRock Azure VM and execute the following commands in order to create a dedicated user and configure key-based SSH authentication:
   1. Create the dedicated account First, create the new user account intended for the Claude Desktop IDE:

      ```shellscript
      $ sudo adduser claude_code_user
      ```

   2. Switch to the new user profile Change your current session to operate as the newly created user:

      ```shellscript
      $ sudo su - claude_code_user
      ```

   3. Generate an SSH keypair Run the `ssh-keygen` command. This will automatically create the `.ssh` directory with the correct permissions.

      ```shellscript
      $ ssh-keygen -t ed25519 -C "your_email@example.com"
      ```

      <div data-gb-custom-block data-tag="hint" data-style="info" data-icon="notes-sticky" class="hint hint-info"><p><strong>Note:</strong> </p><p>When prompted, press <kbd>Enter</kbd> to accept the default file location, and press <kbd>Enter</kbd> again to leave the passphrase empty</p></div>

   4. Authorize the public key Finally, append the designated public key to the `authorized_keys` file to grant inbound access, and lock down the file's permissions:

      ```shellscript
      $ echo "<insert-public-key-here>" >> ~/.ssh/authorized_keys
      $ chmod 600 ~/.ssh/authorized_keys
      ```
2. Configure the Claude Desktop IDE:\
   In the Claude Desktop IDE interface, click the environment selector menu (typically labeled **Local** in the bottom corner) and select **+ Add SSH host...** from the dropdown list. \
   ![](/files/Ji8P3qTQy8EtJcLmPvQC)\
   In the Add SSH connection dialog box, populate the fields with the following parameters:
   1. SSH Connection Name: `<custom-name>`
   2. SSH Host: `claude_code_user@<azure_vm_ip>`
   3. SSH Port: `22` (default)
   4. Identity file: `<path-to-private-key>` \
      ![](/files/ZuUOW39o6da3pCsvnqTD)
3. Initialize the Remote Workspace:
   1. Upon successful SSH connection to the remote VM, select the project folder. Either the default home directory (`/home/claude_code_user`) or a newly created subfolder (e.g., `project`) can be used.
   2. The Claude code session initializes in the background on the remote VM. Code generation occurs directly within the remote workspace based on instructions provided in the IDE chat interface.
4. Telemetry and Event Tracking:\
   The BlueRock agent actively monitors this remote workspace and generates OpenTelemetry (OTEL) events for all Claude code actions, including file operations and forked/executed processes. These events are automatically forwarded to the configured Azure Log Analytics workspace for security monitoring.

{% hint style="info" icon="notes-sticky" %}
**Note:**&#x20;

W*hen prompted, press Enter to accept the default file location, and press Enter again to leave the passphrase empty*
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.bluerock.io/deployment-guides/azure-deployments/azure-deployment-with-cli.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
