Canonical properties for credentials
Summary of the new feature / enhancement
As a user I would like canonical properties for credential fields so that resources use the same convention.
Proposed technical implementation details (optional)
Some example properties:
_username_password_token
_password and _token could be combined to be a generic that accounts for all types of secrets, maybe a _secret property.
A few considerations:
- Some resources require multiple secrets of the same kind (such as credentials for authenticating to a service and a second credential being created).
- Rather than separate properties for username and password, I would prefer a
_credentialcanonical property that defines the identity and secret. - To address the first item, we should probably define the
_credentialand_secretcanonical properties as well as the^_(?<prefix>[a-z][a-zA-Z]*)Credentialand^_(?<prefix>[a-z][a-zA-Z]*)Secretcanonical pattern properties. - We can't provide much in the way of validation for the actual string values in these canonical properties because that varies so widely between implementations. We can show resource authors how to extend the definition usefully, such as adding annotation keywords for documentation and additional validation, like applying a pattern to the
identityfield in the_credentialproperty.
The schemas for this would look something like:
_secret canonical property schema
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
title: Secret
writeOnly: true
type: string
examples:
- $comment: >-
This example resource instance schema defines the `_secret` canonical property.
title: MyResource
type: object
required: [name, _secret]
properties:
name:
type: string
_secret:
$ref: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
- $comment: >-
This example resource instance schema defines the `_fooApiSecret` and `_barApiSecret`
canonical pattern properties.
title: MyResource
type: object
required: [name, _fooApiSecret, _barApiSecret]
properties:
name:
type: string
_fooApiSecret:
$ref: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
_barApiSecret:
$ref: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
_credential canonical property schema
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
title: Credential
writeOnly: true
type: object
unevaluatedProperties: false
minProperties: 1 # Must define either or both identity/secret
properties:
identity:
title: Credential identity
type: string
secret:
title: Credential secret
$ref: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
examples:
- $comment: >-
This example resource instance schema defines the `_credential` canonical property. It
extends the definition for the canonical property to restrict the characters in the
identity.
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://contoso.com/schemas/example/resource.json
type: object
required: [name, _credential]
properties:
name: { type: string }
_credential:
$ref: https://aka.ms/dsc/schemas/v3/resource/properties/credential.json
title: Service authentication credential
description: Authenticates to the service.
required: [identity, secret]
properties:
identity:
title: Service authentication identity
description: >-
Defines the identity to authenticate with. Must be a string of
alphanumeric characters and underscores between 5 and 15 characters
long.
pattern: ^\w+$
minLength: 5
maxLength: 15
- $comment: >-
This example resource instance schema defines the `_fooCredential` and `_barCredential`
canonical pattern properties without overriding.
title: MyResource
type: object
required: [name, _fooApiCredential, _barApiCredential]
properties:
name:
type: string
_fooApiCredential:
$ref: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
_barApiCredential:
$ref: https://aka.ms/dsc/schemas/v3/resource/properties/secret.json
Thinking about this and doing some local testing, I think this model does broadly work and would enable us to always mark these canonical properties (and canonical pattern properties) as secret internally, to limit the risk of leaking secrets. What we can't currently do without an extended vocabulary is explicitly indicate that these values are secret in the JSON Schema, except by our convention.
When we define the extended vocabulary, we should probably define a keyword like x-dsc-isSecret or x-dsc-isSensitive to clearly indicate that a value should always be redacted. Then, even for values that don't map to these canonical properties, DSC can either require the user pass the values as secrets or redact the values regardless of whether the user passed them as a secret. The latter is probably helpful for sensitive/secret values whose subschema defines the keyword but aren't objects or strings (and so the internal data model inherited from ARM doesn't have a way to automatically redact those values).