-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DSC meta configuration #282
Comments
My vote is for a json configuration file sitting next to |
I'm fine with either/or JSON or YAML, and we can readily schematize the configuration file for documenting/editing. I think a DSC Resource to read/modify it is perfectly sensible, could just be calling |
|
DSC meta settingsThis document describes potential settings for DSC's meta configuration. There are six Note The settings in the examples use snake-case and YAML. This is for readability in the proposal,
Configuration fileThe configuration file that contains the meta settings should be located with File name json: P0 -----------------------Resource discovery path
Users should be able to define an array of directories that DSC should search for non-built-in
Example settingsWith an empty configuration file# settings.dsc.yaml
---
# Effective settings
resource_path:
allow_env_override: true
append_env_path: true
directories: null With directories defined# settings.dsc.yaml
resource_path:
directories:
- '/ops/dsc/resources'
- '/app/dsc'
---
# Effective settings
resource_path:
allow_env_override: false
append_env_path: false
directories:
- '/ops/dsc/resources'
- '/app/dsc' With directories defined and
|
Array | Effect |
---|---|
[] |
Forbid the command entirely. |
[from_document] |
Forbid passing a configuration document from stdin or as an argument. Only allow using configuration documents saved as files. |
[from_input] |
Forbid specifying the path to a configuration document saved as a file. Only allow using configuration documents passed from stdin or as an argument. (Unlikely to be used). |
[from_document , from_input ] |
Allow command regardless of how the configuration document is passed. |
When users define a list of allowed documents, forbid passing documents from input by default for
the set command, including in what-if mode
When passing a document by file path with a defined allow list, always raise an error for
documents outside the allow list for set commands regardless of mode.
When passing a document from stdin or argument with a defined allow list, raise a warning when
the SHA of the document doesn't match the SHA of an allowed document.
For configurations that include other configurations, the included configurations must also be
allowed or DSC should raise an error (to prevent a malicious actor from altering an included
configuration to inject misbehavior into a trusted document).
Example settings
When configuration
isn't specified in settings
# settings.dsc.yaml
---
# Effective settings
configuration:
operations:
export: [from_input, from_document]
get: [from_input, from_document]
test: [from_input, from_document]
whatIf: [from_input, from_document]
set: [from_input, from_document]
With an allow list for configuration documents
# settings.dsc.yaml
configuration:
allow_documents:
- /ops/dsc/configs/* # simple string as file glob
- path: /app/dsc/web.dsc.json # object with advanced options
sha256: <sha>
---
# Effective settings
configuration:
allow_documents:
- path: /ops/dsc/configs/*
- path: /app/dsc/web.dsc.json
sha256: <sha>
operations:
export: [from_input, from_document]
get: [from_input, from_document]
test: [from_input, from_document]
whatIf: [from_document]
set: [from_document]
With an allow list and forbidding export
# settings.dsc.yaml
configuration:
allow_documents:
- /ops/dsc/configs/* # simple string as file glob
- path: /app/dsc/web.dsc.json # object with advanced options
sha256: <sha>
operations:
export: false # convenience, could also be empty array
---
# Effective settings
configuration:
allow_documents:
- path: /ops/dsc/configs/*
- path: /app/dsc/web.dsc.json
sha256: <sha>
operations:
export: []
get: [from_input, from_document]
test: [from_input, from_document]
whatIf: [from_document]
set: [from_document]
With an allow list and boolean operation values
# settings.dsc.yaml
configuration:
allow_documents:
- /ops/dsc/configs/* # simple string as file glob
- path: /app/dsc/web.dsc.json # object with advanced options
sha256: <sha>
operations:
export: false
get: true
test: true
whatIf: true
set: true
---
# Effective settings
configuration:
allow_documents:
- path: /ops/dsc/configs/*
- path: /app/dsc/web.dsc.json
sha256: <sha>
operations:
export: []
get: [from_input, from_document]
test: [from_input, from_document]
whatIf: [from_document]
set: [from_document]
With boolean operation values and without an allow list
configuration:
allow_documents:
- /ops/dsc/configs/* # simple string as file glob
- path: /app/dsc/web.dsc.json # object with advanced options
sha256: <sha>
operations:
export: []
get: true
test: true
whatIf: true
set: true
---
# Effective settings
configuration:
operations:
export: []
get: [from_input, from_document]
test: [from_input, from_document]
whatIf: [from_input, from_document]
set: [from_input, from_document]
With fully explicit settings
configuration:
allow_documents:
- /ops/dsc/configs/* # simple string as file glob
- path: /app/dsc/web.dsc.json # object with advanced options
sha256: <sha>
operations:
export: []
get: [from_document]
test: [from_document]
whatIf: [from_document]
set: [from_document]
---
# Effective settings
configuration:
allow_documents:
- path: /ops/dsc/configs/*
- path: /app/dsc/web.dsc.json
sha256: <sha>
operations:
export: []
get: [from_document]
test: [from_document]
whatIf: [from_document]
set: [from_document]
Allow listing resources and invocation operations
As an infrastructure engineer, I want to define an allow list for resources that can be invoked
or included in a configuration document.
As an infrastructure engineer, I want to limit the
dsc resource <operation>
commands that can be
executed to ensure stronger control over how users can query and modify our systems.
The most coherent approach to this seems to be enabling users to define a list of allowed resources
with optional additional restrictions. Users may prefer to define this list by path or by type or
both. This check should be independent of discovery, which uses the
resource_path
settings.
For resource invocation, it probably makes the most sense to define a map of boolean values to
operations, true
enabling direct invocation and false
forbidding it for a given operation. For
simplicity, users should be able to specify true
or false
to allow/forbid all direct invocation
operations.
These settings should:
- Enable users to define whether to allow use of built-in resources (suspect this will always be
true, but perhaps an org forbids them for some reason?) - Enable users to specify file globs for the paths to allowed resources, with optional restrictions
like SHA, signature, version range, etc. - Enable users to specify name globs for the types of allowed resources, with optional restrictions.
- Enable users to specify which DSC resource invocation operations are allowed.
- Enable users to specify
true
orfalse
for the setting that allows invocations to indicate
whether to allow or forbid invocations in general. - If the settings don't specifically define which invocation operations are allowed, forbid
set
anddelete
when the settings explicitly define any allowed configuration documents to prevent
one-by-one changes to the system outside of the allowed configurations. - If the settings define allowed invocation operations as
true
, still forbidset
anddelete
when the settings also define a list of allowed configuration documents.
Example settings
With an empty configuration file
# settings.dsc.yaml
---
# Effective settings
resource:
allow_built_in: true
allow_invocation:
get: true
test: true
set: true
export: true
delete: true
With a list of allowed documents
# settings.dsc.yaml
configuration:
allow_documents:
- /ops/dsc/configs/* # simple string as file glob
- path: /app/dsc/web.dsc.json # object with advanced options
sha256: <sha>
---
# Effective settings
configuration:
allow_documents:
- path: /ops/dsc/configs/*
- path: /app/dsc/web.dsc.json
sha256: <sha>
operations:
export: [from_input, from_document]
get: [from_input, from_document]
test: [from_input, from_document]
whatIf: [from_document]
set: [from_document]
resource:
allow_built_in: true
allow_invocation:
get: true
test: true
set: false
export: true
delete: false
With a list of allowed documents and allow all invocations
# settings.dsc.yaml
configuration:
allow_documents:
- /ops/dsc/configs/* # simple string as file glob
- path: /app/dsc/web.dsc.json # object with advanced options
sha256: <sha>
resource:
allow_invocation: true
---
# Effective settings
configuration:
allow_documents:
- path: /ops/dsc/configs/*
- path: /app/dsc/web.dsc.json
sha256: <sha>
operations:
export: [from_input, from_document]
get: [from_input, from_document]
test: [from_input, from_document]
whatIf: [from_document]
set: [from_document]
resource:
allow_built_in: true
allow_invocation:
get: true
test: true
set: false
export: true
delete: false
With all invocations forbidden
# settings.dsc.yaml
resource:
allow_invocation: false
---
# Effective settings
resource:
allow_built_in: true
allow_invocation:
get: false
test: false
set: false
export: false
delete: false
With resources allowed by path
# settings.dsc.yaml
resource:
allow_paths:
- /ops/dsc/resources/* # simple string as file glob
- path: /app/dsc/resources/web.dsc.resource.json # object with advanced options
sha256: <sha>
---
# Effective settings
resource:
allow_built_in: true
allow_paths:
- path: /ops/dsc/resources/*
- path: /app/dsc/resources/web.dsc.resource.json
sha256: <sha>
allow_invocation:
get: false
test: false
set: false
export: false
delete: false
With resources allowed by type
# settings.dsc.yaml
resource:
allow_types:
- Microsoft.SqlServer* # Simple string as type glob
- type: TSToy* # object with advanced options
require_signature: true
---
# Effective settings
resource:
allow_built_in: true
allow_types:
- type: Microsoft.SqlServer*
- type: TSToy*
require_signature: true
allow_invocation:
get: false
test: false
set: false
export: false
delete: false
With resources allowed by path and type
# settings.dsc.yaml
resource:
allow_paths:
- /ops/dsc/resources/* # simple string as file glob
- path: /app/dsc/resources/web.dsc.resource.json # object with advanced options
sha256: <sha>
allow_types:
- Microsoft.SqlServer* # Simple string as type glob
- type: TSToy* # object with advanced options
require_signature: true
---
# Effective settings
resource:
allow_built_in: true
allow_paths:
- path: /ops/dsc/resources/*
- path: /app/dsc/resources/web.dsc.resource.json
sha256: <sha>
allow_types:
- type: Microsoft.SqlServer*
- type: TSToy*
require_signature: true
allow_invocation:
get: true
test: true
set: true
export: true
delete: true
resource:
# Allow use of built-in resources, like `Microsoft.DSC/Group`
allow_built_in: true # default
# Define allowed resources by path glob
allow_paths:
# simple string as file glob
- /ops/dsc/resources
# object with advanced options
- path: /app/dsc/resources/web.dsc.resource.json
sha256: <sha>
# Define allowed resources by type glob
allow_types:
# Simle string as type glob
- Microsoft.*
# object with advanced options
- type: Microsoft.SqlServer*
require_signature: true
allow_invocation:
get: true
test: true
set: true
export: true
delete: true
Require version pins in configurations
As an infrastructure engineer, I want to ensure that my configurations are as deterministic as
possible without relying entirely on manual verification by having DSC reject configuration
documents with resource instances that don't declare their version pin.
Currently, DSC doesn't support version pinning per resource instance or configuration. To help
users ensure deterministic configurations, we should have an opt-in setting that requires version
pins for resources in a configuration.
When DSC is set to require version pinning, it should fail the validation for any passed configuration
that includes one or more instances without a version pin. The error should collect all such instances
and report them in the error message, not just the first invalid resource instance.
Example settings
With an empty configuration file
# settings.dsc.yaml
---
# Effective settings
configuration:
require_version_pinning: false
With the setting defined
# settings.dsc.yaml
configuration:
require_version_pinning: true
---
# Effective settings
configuration:
require_version_pinning: true
Require verified documents and resources
As an infrastructure engineer, I want to require all configuration documents and resources to be
signed by a trusted persona so that I can have increased trust in the resources that modify my
systems.
As an infrastructure engineer, I want to require all configuration documents and resources to
have a software bill of materials (SBOM) to comply with policies/regulations and have increased
confidence in the provenance of code that modifies my systems.
This requires answering questions about signing configurations and resources, and having a trust
model for DSC. This must be deferred until those domains are handled, but should be considered when
implementing them.
If signatures are required, any operation that includes an unsigned configuration document or
resource should raise an error indicating the document or resource isn't signed. Users should be
able to specify whether to require signatures for either or both, and to override on a per-document
level for explicitly allowed documents.
If SBOMs are required, any operation that includes a configuration or resource without one should
raise an error indicating what items are missing an SBOM. Users should be able to specify whether
to require SBOMs for either or both, and to override the setting on a per-resource level for
explicitly allowed resources.
The following code snippet is a gesture in this direction, but I don't have the familiarity with
signing or SBOMs to have a better idea at this time.
# Settings to define what DSC trusts for verifying signatures
verification:
trusted_authorities: # Define a list of authorities to use for verification
trusted_personas: # Define a subset of personas to trust
require_signature: false # Define whether to require signatures for resources and documents
require_sbom: false # Define whether to require SBOMs for
# Configuration settings
configuration:
require_signature: true # Overrides verification.require_signature
require_sbom: true # Overrides verification.require_sbom
allow_documents:
# Allow all documents in this folder (require sbom and signature)
- /ops/dsc/configs/*
# Allow all documents signed by this persona, regardless of path
- signed_by: <trusted persona>
# Allow all documents in the folder & signed by the ops team
- path: /ops/dsc/configs/*
signed_by: <ops team persona>
# Allow this document without sbom, require signature
- path: /temp/debug.dsc.config.yaml
require_sbom: false
resource:
require_signature: true # Overrides verification.require_signature
require_sbom: true # overrides verification.require_sbom
allow_types:
# Allow all resources in this namespace (require sbom and signature)
- MyOrg*
# Allow all resources signed by this persona, regardless of type
- signed_by: <trusted persona>
# Allow all resources in this namespace signed by the ops team
- type: MyOrg.Ops*
signed_by: <ops team persona>
# Allow this resource without sbom, require signature
- type: MyOrg.Debug/TelemetryTrace
Remote discovery
Footnotes
-
DSC currently defines the
DSC_RESOURCE_PATH
environment variable. We should consider
renaming this toDSC_DISCOVERY_PATH
if we plan to support publishing configurations or
supporting extensions (#), or accept that we'll need to define new
DSC_CONFIGURATION_PATH
/DSC_EXTENSION_PATH
environment variables later, or that
DSC_RESOURCE_PATH
will also be used to find non-resource items. ↩
Per discussion for 3.0, we'll only implement the P0 items. Current thinking is to have a |
I would recommend using |
I like the idea of having a Settings file with each resource / configuration used as an override to the higher level Settings. This is similar to how it is done in Bicep as well. This would allow for more complex configurations where some resources are allowed to change state, while other potentially disruptive |
Summary of the new feature / enhancement
Right now, there's no persistent way for a user to control how
dsc
behaves except for theDSC_RESOURCE_PATH
environmental variable. Users may want to set the default output format for DSC to pretty-json, or only use manifests that have been signed, or disable specific providers (see #274).As the options for how
dsc
should behave expand, these needs will compound - consider theWhatIf
scenario, whether to pre-check for permissions, etc.Proposed technical implementation details (optional)
I haven't done much research on the available options for rust applications, but in an ideal world, we could borrow (a subset of) the functionality that viper has, supporting layered overrides, where each item in the following list takes precedence over the item below it:
--format
DSC_FORMAT
format
Even if we only supported flags and environment variables, I think we'd have a more manageable UX. We could implement the configuration file handling later, if ever. With support for using environment variables as default options, users could use
.env
files as lightweight configuration, or set the variables in their CI jobs, or whatever makes sense for their context.The text was updated successfully, but these errors were encountered: