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
2 changes: 1 addition & 1 deletion docs/excluding-from-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This type of exclusion is expressed by passing an array of resource names into e

All supported resource values for exclusion:

`actions`, `attackProtection`, `branding`, `clientGrants`, `clients`, `connections`, `customDomains`, `databases`, `emailProvider`, `emailTemplates`, `guardianFactorProviders`, `guardianFactorTemplates`, `guardianFactors`, `guardianPhoneFactorMessageTypes`, `guardianPhoneFactorSelectedProvider`, `guardianPolicies`, `logStreams`, `migrations`, `organizations`, `pages`, `prompts`, `resourceServers`, `roles`, `tenant`, `triggers`,`selfServiceProfiles`.
`actions`, `attackProtection`, `branding`, `clientGrants`, `clients`, `connections`, `customDomains`, `databases`, `emailProvider`, `emailTemplates`, `guardianFactorProviders`, `guardianFactorTemplates`, `guardianFactors`, `guardianPhoneFactorMessageTypes`, `guardianPhoneFactorSelectedProvider`, `guardianPolicies`, `logStreams`, `migrations`, `networkACLKeys`, `networkACLs`, `organizations`, `pages`, `prompts`, `resourceServers`, `roles`, `tenant`, `triggers`, `selfServiceProfiles`.

### Exclusion Example

Expand Down
83 changes: 83 additions & 0 deletions docs/resource-specific-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,89 @@ Contents of `Block iCloud Private Relay Exits-p-4.json`:
}
```

## NetworkACL Keys

Network ACL Keys are HMAC signing keys used for [HTTP message signature verification](https://auth0.com/docs/secure/tenant-access-control-list) in Network ACL rules. Each key has a name, an algorithm (`hmac-sha256`), and a server-computed fingerprint. The Deploy CLI supports creating and deleting NetworkACL keys.

> **Note:** This feature requires the `tenant_acl_hmac_signature` and `tenant_acl_management_api` feature flags plus the `tenant-access-control` entitlement. Contact Auth0 support if the feature is not available on your tenant.

NetworkACL keys have the following properties:

- `name`: Unique name for the key (max 255 characters)
- `alg`: Signing algorithm — currently only `hmac-sha256`
- `value`: The raw key material (**write-only** — never returned by the API, not exported). Supply via keyword replacement (e.g. `##HMAC_KEY_VALUE##`) mapped from an environment variable or CI secret.
- `fingerprint`: SHA-256 fingerprint of the key (read-only, set by the API, exported for reference)

Keys are **immutable** after creation. To rotate a key, delete the old one and create a new one with a different name.

> **Warning:** Deleting a key that is still referenced by an ACL rule will return HTTP 409. Remove all rule references first.

### Supplying the key value

The `value` field is write-only and is never returned by the API. At deploy time, supply it using keyword replacement:

```yaml
# config.json (or environment variables)
# HMAC_KEY_VALUE=<your-secret-key-material>

# tenant.yaml
networkACLKeys:
- name: my-hmac-key-v1
alg: hmac-sha256
value: ##HMAC_KEY_VALUE##
```

If `value` is omitted from the config, the Deploy CLI will log a warning and skip creating that key. This is useful for tracking existing keys (by name and fingerprint) without re-supplying the secret.

**YAML Example**

```yaml
# Contents of ./tenant.yaml
networkACLKeys:
- name: my-hmac-key-v1
alg: hmac-sha256
value: ##HMAC_KEY_VALUE## # omitted on export; supply at deploy time
fingerprint: ee66b47a0b3e356a0d7c587bd1e2ed3790b46fdbd657dbeb409f30de76a14cc3
```

**Directory Example**

```
Folder structure when in directory mode.

./network-acl-keys/
./my-hmac-key-v1.json
```

Contents of `my-hmac-key-v1.json`:

```json
{
"name": "my-hmac-key-v1",
"alg": "hmac-sha256",
"fingerprint": "ee66b47a0b3e356a0d7c587bd1e2ed3790b46fdbd657dbeb409f30de76a14cc3"
}
```

### Using a key in a NetworkACL rule

Once a key is deployed, reference it by `id` in an ACL rule's `http_message_signature` signal:

```yaml
networkACLs:
- description: 'Require HMAC signature'
active: true
priority: 1
rule:
action:
allow: true
scope: 'authentication'
match:
http_message_signature:
keys:
- id: <key-id> # the id returned by the API after key creation
```

## Organizations

The deploy CLI supports managing organizations, including their connections, client grants, discovery domains, and org-to-app entitlement settings.
Expand Down
5 changes: 5 additions & 0 deletions examples/directory/network-acl-keys/my-hmac-key-v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "my-hmac-key-v1",
"alg": "hmac-sha256",
"fingerprint": "ee66b47a0b3e356a0d7c587bd1e2ed3790b46fdbd657dbeb409f30de76a14cc3"
}
7 changes: 7 additions & 0 deletions examples/yaml/tenant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,13 @@ selfServiceProfiles:
description: Name of the User
is_optional: true

networkACLKeys:
- name: my-hmac-key-v1
alg: hmac-sha256
# value is write-only and never exported. Supply at deploy time via keyword replacement:
# value: ##HMAC_KEY_VALUE##
fingerprint: ee66b47a0b3e356a0d7c587bd1e2ed3790b46fdbd657dbeb409f30de76a14cc3

networkACLs:
- description: 'Allow Specific Countries'
active: true
Expand Down
2 changes: 2 additions & 0 deletions src/context/directory/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import rulesConfigs from './rulesConfigs';
import forms from './forms';
import flows from './flows';
import flowVaultConnections from './flowVaultConnections';
import networkACLKeys from './networkACLKeys';
import networkACLs from './networkACLs';
import userAttributeProfiles from './userAttributeProfiles';
import connectionProfiles from './connectionProfiles';
Expand Down Expand Up @@ -90,6 +91,7 @@ const directoryHandlers: {
flows,
flowVaultConnections,
selfServiceProfiles,
networkACLKeys,
networkACLs,
userAttributeProfiles,
connectionProfiles,
Expand Down
66 changes: 66 additions & 0 deletions src/context/directory/handlers/networkACLKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import path from 'path';
import fs from 'fs-extra';
import { constants } from '../../../tools';
import { getFiles, existsMustBeDir, dumpJSON, loadJSON, sanitize } from '../../../utils';
import { DirectoryHandler } from '.';
import DirectoryContext from '..';
import { ParsedAsset } from '../../../types';
import { NetworkAclKey } from '../../../tools/auth0/handlers/networkACLKeys';
import log from '../../../logger';

type ParsedNetworkACLKeys = ParsedAsset<'networkACLKeys', NetworkAclKey[]>;

function parse(context: DirectoryContext): ParsedNetworkACLKeys {
const networkACLKeysDirectory = path.join(context.filePath, constants.NETWORK_ACL_KEYS_DIRECTORY);
if (!existsMustBeDir(networkACLKeysDirectory)) return { networkACLKeys: null }; // Skip

const foundFiles = getFiles(networkACLKeysDirectory, ['.json']);

const networkACLKeys = foundFiles
.map((f) =>
loadJSON(f, {
mappings: context.mappings,
disableKeywordReplacement: context.disableKeywordReplacement,
})
)
.filter((p) => Object.keys(p).length > 0); // Filter out empty configs

return {
networkACLKeys,
};
}

async function dump(context: DirectoryContext): Promise<void> {
const { networkACLKeys } = context.assets;

if (!networkACLKeys) return; // Skip, nothing to dump

if (Array.isArray(networkACLKeys) && networkACLKeys.length === 0) {
log.info('No network ACL keys available, skipping dump');
return;
}

const networkACLKeysDirectory = path.join(context.filePath, constants.NETWORK_ACL_KEYS_DIRECTORY);
fs.ensureDirSync(networkACLKeysDirectory);

// value is write-only — never returned by the API and must not be exported.
// created_at and updated_at are API-generated metadata; not needed in config.
const removeKeysFromOutput = ['value', 'created_at', 'updated_at'];

networkACLKeys.forEach((networkACLKey) => {
const out = { ...networkACLKey };
removeKeysFromOutput.forEach((key) => {
if (key in out) delete out[key];
});
const fileName = sanitize(networkACLKey.name);
const filePath = path.join(networkACLKeysDirectory, `${fileName}.json`);
dumpJSON(filePath, out);
});
}

const networkACLKeysHandler: DirectoryHandler<ParsedNetworkACLKeys> = {
parse,
dump,
};

export default networkACLKeysHandler;
2 changes: 2 additions & 0 deletions src/context/yaml/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import hooks from './hooks';
import forms from './forms';
import flows from './flows';
import flowVaultConnections from './flowVaultConnections';
import networkACLKeys from './networkACLKeys';
import networkACLs from './networkACLs';
import userAttributeProfiles from './userAttributeProfiles';
import connectionProfiles from './connectionProfiles';
Expand Down Expand Up @@ -88,6 +89,7 @@ const yamlHandlers: { [key in AssetTypes]: YAMLHandler<{ [key: string]: unknown
flows,
flowVaultConnections,
selfServiceProfiles,
networkACLKeys,
networkACLs,
userAttributeProfiles,
connectionProfiles,
Expand Down
51 changes: 51 additions & 0 deletions src/context/yaml/handlers/networkACLKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { YAMLHandler } from '.';
import YAMLContext from '..';
import { ParsedAsset } from '../../../types';
import { NetworkAclKey } from '../../../tools/auth0/handlers/networkACLKeys';
import log from '../../../logger';

type ParsedNetworkACLKeys = ParsedAsset<'networkACLKeys', NetworkAclKey[]>;

async function parse(context: YAMLContext): Promise<ParsedNetworkACLKeys> {
const { networkACLKeys } = context.assets;

if (!networkACLKeys) return { networkACLKeys: null };

return {
networkACLKeys,
};
}

async function dump(context: YAMLContext): Promise<ParsedNetworkACLKeys> {
let { networkACLKeys } = context.assets;

if (!networkACLKeys) return { networkACLKeys: null };

if (Array.isArray(networkACLKeys) && networkACLKeys.length === 0) {
log.info('No network ACL keys available, skipping dump');
return { networkACLKeys: null };
}

// value is write-only — never returned by the API and must not be exported.
// created_at and updated_at are API-generated metadata; not needed in config.
const removeKeysFromOutput = ['value', 'created_at', 'updated_at'];

networkACLKeys = networkACLKeys.map((key) => {
const out = { ...key };
removeKeysFromOutput.forEach((k) => {
if (k in out) delete out[k];
});
return out;
});

return {
networkACLKeys,
};
}

const networkACLKeysHandler: YAMLHandler<ParsedNetworkACLKeys> = {
parse,
dump,
};

export default networkACLKeysHandler;
2 changes: 2 additions & 0 deletions src/tools/auth0/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import * as forms from './forms';
import * as flows from './flows';
import * as flowVaultConnections from './flowVaultConnections';
import * as selfServiceProfiles from './selfServiceProfiles';
import * as networkACLKeys from './networkACLKeys';
import * as networkACLs from './networkACLs';
import * as userAttributeProfiles from './userAttributeProfiles';
import * as connectionProfiles from './connectionProfiles';
Expand Down Expand Up @@ -85,6 +86,7 @@ const auth0ApiHandlers: { [key in AssetTypes]: any } = {
flows,
flowVaultConnections,
selfServiceProfiles,
networkACLKeys,
networkACLs,
userAttributeProfiles,
connectionProfiles,
Expand Down
Loading