# OVHcloud

> Connect OVHcloud to Tidal Control with an OAuth2 service account using the client credentials flow, so compliance tests read your account's security settings.

Source: https://tidalcontrol.com/docs/integrations/ovhcloud

Tidal Control's OVHcloud integration monitors your account's security configuration for compliance purposes. It uses an **OAuth2 service account** (client credentials flow) to authenticate against the OVHcloud v1 and v2 APIs.

## What this integration monitors

- **IAM users (sub-users):** Account identity inventory
- **IAM groups:** Group membership
- **IAM policies:** Access policy configuration
- **Legacy API applications and credentials:** Older API access
- **OAuth2 service accounts:** Service-account inventory
- **Public Cloud projects:** Project inventory
- **Cloud project users:** Per-project users
- **SSH keys:** Cloud SSH credential inventory
- **Cloud instances:** Compute inventory
- **Managed databases:** Database services
- **KMS resources:** Key Management Service inventory

## Requirements

- Super User role in Tidal Control
- OVHcloud account with access to the API console and IAM
- The EU endpoint (`https://api.eu.ovhcloud.com`), the only region supported at this time

> **info:**

**Security groups are not included.** OVHcloud security groups are only available through the OpenStack API, not the OVHcloud REST API, so the connector does not monitor them.

## Configuration step-by-step plan

We'll create an **OAuth2 service account**, copy its **identity URN**, create an **IAM policy** granting read-only access, then add the connection in Tidal Control.

**Configuration steps:**

1. **Create an OAuth2 client (service account)**
2. **Copy the service account's identity URN**
3. **Create an IAM policy**
4. **Configure the integration in Tidal Control**

## Step 1: Create an OAuth2 client (service account)

In the [OVHcloud Manager API console](https://manager.eu.ovhcloud.com/beta/#/api), execute:

```
POST /me/api/oauth2/client
{
  "callbackUrls": [],
  "flow": "CLIENT_CREDENTIALS",
  "name": "tidal-control",
  "description": "Tidal Control security compliance connector"
}
```

Save the returned `clientId` and `clientSecret`.

Alternatively, go to **Account & Billing → My Account → My identities → Service accounts → Create**.

> **warning:**

**Save the client secret immediately.** The `clientSecret` is shown only once. If you lose it, create a new OAuth2 client.

## Step 2: Copy the service account's identity URN

After creating the client, call:

```
GET /me/api/oauth2/client/{clientId}
```

Copy the `identity` field. It looks like:

```
urn:v1:eu:identity:credentialOAuth2:{nicHandle}/EU.xxxxxxxxxxxxxxxx
```

Your **nicHandle** is shown in the top-right menu of the OVHcloud Manager (e.g. `hw53544-ovh`).

## Step 3: Create an IAM policy

Create a read-only IAM policy for the service account. You can do this in **IAM → Policies → Create a policy** in the Manager, or via the API.

> **warning:**

**Use explicit resource URNs, not a wildcard.** Using `urn:v1:eu:resource:*:*` fails with an error such as *"a policy can't target subusers of another account"*, because the wildcard expands to resources from every account linked to the root account. List each resource explicitly instead.

**Resources.** Add one entry per resource type you have:

<table>
<thead>
<tr><th>Resource type</th><th>URN format</th></tr>
</thead>
<tbody>
<tr><td>Account (for <code>me/&#42;</code> and <code>iam/&#42;</code> endpoints)</td><td><code>urn:v1:eu:resource:account:&#123;nicHandle&#125;</code></td></tr>
<tr><td>Cloud project (one per project)</td><td><code>urn:v1:eu:resource:publicCloudProject:&#123;projectId&#125;</code></td></tr>
<tr><td>KMS (one per resource)</td><td><code>urn:v1:eu:resource:okms:&#123;kmsId&#125;</code></td></tr>
</tbody>
</table>

**Allowed actions.** Grant exactly these read actions. Note that cloud-project actions use the `publicCloudProject:apiovh:` prefix, not `account:apiovh:cloud/project/`:

<table>
<thead>
<tr><th>Purpose</th><th>Action</th></tr>
</thead>
<tbody>
<tr><td>IAM sub-users</td><td><code>account:apiovh:me/identity/user/get</code></td></tr>
<tr><td>IAM groups</td><td><code>account:apiovh:me/identity/group/get</code></td></tr>
<tr><td>Legacy API applications</td><td><code>account:apiovh:me/api/application/get</code></td></tr>
<tr><td>Legacy API credentials</td><td><code>account:apiovh:me/api/credential/get</code></td></tr>
<tr><td>Service accounts (OAuth2 clients)</td><td><code>account:apiovh:me/api/oauth2/client/get</code></td></tr>
<tr><td>IAM policies</td><td><code>account:apiovh:iam/policy/get</code></td></tr>
<tr><td>Public Cloud projects</td><td><code>publicCloudProject:apiovh:get</code></td></tr>
<tr><td>Cloud project users</td><td><code>publicCloudProject:apiovh:user/get</code></td></tr>
<tr><td>SSH keys</td><td><code>publicCloudProject:apiovh:sshkey/get</code></td></tr>
<tr><td>Cloud instances</td><td><code>publicCloudProject:apiovh:instance/get</code></td></tr>
<tr><td>Managed databases</td><td><code>publicCloudProject:apiovh:database/service/get</code></td></tr>
<tr><td>KMS resources</td><td><code>okms:apiovh:resource/get</code></td></tr>
</tbody>
</table>

Creating the policy via the API:

```bash
# First get a token
TOKEN=$(curl -s -X POST https://www.ovh.com/auth/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials&scope=all" | jq -r '.access_token')

# Create the IAM policy
curl -s -X POST https://api.eu.ovhcloud.com/v2/iam/policy \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "tidal-control",
    "description": "Tidal Control read-only access",
    "identities": ["urn:v1:eu:identity:credentialOAuth2:{nicHandle}/EU.xxxxxxxxxxxxxxxx"],
    "resources": [
      "urn:v1:eu:resource:account:{nicHandle}",
      "urn:v1:eu:resource:publicCloudProject:{projectId}",
      "urn:v1:eu:resource:okms:{kmsId}"
    ],
    "permissions": {
      "allow": [
        {"action": "account:apiovh:me/identity/user/get"},
        {"action": "account:apiovh:me/identity/group/get"},
        {"action": "account:apiovh:me/api/application/get"},
        {"action": "account:apiovh:me/api/credential/get"},
        {"action": "account:apiovh:me/api/oauth2/client/get"},
        {"action": "account:apiovh:iam/policy/get"},
        {"action": "publicCloudProject:apiovh:get"},
        {"action": "publicCloudProject:apiovh:user/get"},
        {"action": "publicCloudProject:apiovh:sshkey/get"},
        {"action": "publicCloudProject:apiovh:instance/get"},
        {"action": "publicCloudProject:apiovh:database/service/get"},
        {"action": "okms:apiovh:resource/get"}
      ]
    }
  }'
```

Replace `{nicHandle}`, `{projectId}`, `{kmsId}` and the identity URN with your actual values. Add one `resources` entry per cloud project and per KMS resource.

## Step 4: Configure the integration in Tidal Control

- Go to **Settings → Integrations** in Tidal Control
- Click the **plus icon** next to **OVHcloud**
- Fill in the configuration:
  - **Name:** A descriptive name, e.g. `OVHcloud`
  - **Client ID:** The `clientId` from step 1 (e.g. `EU.xxxxxxxxxxxxxxxx`)
  - **Client Secret:** The `clientSecret` from step 1
- Click **"Create"** to save the integration

## Configuration fields explained

The integration dialog asks for the following values:

**Name:**
- A descriptive name for this connection
- For example: `OVHcloud`, `OVHcloud Production`

**Client ID:**
- The `clientId` of the OAuth2 service account created in step 1
- For example: `EU.xxxxxxxxxxxxxxxx`

**Client Secret:**
- The `clientSecret` of the OAuth2 service account
- Shown only once at creation. Keep it secure

> **info:**

**How authentication works.** The connector requests a token from `https://www.ovh.com/auth/oauth2/token` using HTTP Basic auth (`Authorization: Basic base64(clientId:clientSecret)`) with `grant_type=client_credentials&scope=all`, then calls the EU API base `https://api.eu.ovhcloud.com`.

## Verification

The integration is working when all of the following are true:

- Settings → Integrations shows OVHcloud under **Configured Integrations**
- OVHcloud tests are available in the Tests section
- Test refresh delivers results without authentication errors

## Finding additional action names

If more OVHcloud endpoints need to be covered in the future, the full list of IAM action names can be retrieved from the IAM reference API:

```bash
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.eu.ovhcloud.com/v2/iam/reference/action?resourceType=publicCloudProject" \
  | jq '.[].action'
```

Use `resourceType=account` for `me/*` endpoints and `resourceType=okms` for KMS.

## Common problems

**`"invalid identity ... a policy can't target subusers of another account"`**
- You used the wildcard resource `urn:v1:eu:resource:*:*`
- Replace it with explicit resource URNs (see step 3)

**`"unknown action"` errors**
- A cloud-project action used the wrong prefix
- Cloud-project actions must use `publicCloudProject:apiovh:` (e.g. `publicCloudProject:apiovh:instance/get`), not `account:apiovh:cloud/project/...`

**Authentication fails**
- Confirm the Client ID and Client Secret are correct and the OAuth2 client uses the `CLIENT_CREDENTIALS` flow
- Confirm you are using the EU account (`https://api.eu.ovhcloud.com`)

**Tests show no data for certain resource types**
- Confirm the IAM policy includes the matching action and an explicit resource URN for that resource

### Still can't figure it out?

Send an email to support@tidalcontrol.com, and we'll get back to you as soon as possible.

> **info:**

**Gather support info:** Note which browser you're using, exact error messages, and which steps you've already tried. This speeds up the solution considerably.
