PowerShell / DSC

This repo is for the DSC v3 project
MIT License
214 stars 29 forks source link

Policy resource #558

Open SteveL-MSFT opened 1 month ago

SteveL-MSFT commented 1 month ago

Summary of the new feature / enhancement

Looking at existing Azure policies defined in https://github.com/Azure/azure-policy/blob/master/samples/GuestConfiguration/package-samples/configurations/AzureWindowsBaseline/AzureWindowsBaseline.mof, it seems that it may be useful to have a common Policy resource that can leverage use another resource for the actual get and set, but has a way within the config to have a custom test:

Here's an example policy in mof:

instance of ASM_Registry as $ASM_Registry26ref
{
    RuleId = "{a002b800-92a4-45cb-bbee-76c91739ddff}";
    AzId = "AZ-WIN-00175";
    BaselineId = "{982a79a8-1c46-4fdf-8cfd-60afedf7ad96}";
    OriginalBaselineId = "{9c2bc3d1-8668-48e5-ac5f-281718d52174}";
    Name = "Disable SMB v1 server";
    Severity = "Critical";
    Hive = "HKEY_LOCAL_MACHINE";
    Path = "SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Parameters";
    Value = "SMB1";
    Type = "REG_DWORD";
    ExpectedValue = "0";
    RemediateValue = "0";
    Remediate = true;
    AnalyzeOperation = "EQUALSORNOTEXISTS";
    ServerTypeFilter = "ServerType = [Domain Controller, Domain Member, Workgroup Member]";
    OSFilter = "OSVersion = [WS2008, WS2008R2, WS2012, WS2012R2, WS2016]";
    Enabled = true;
    ResourceID = "Disable SMB v1 server";
    ModuleName = "AzureOSBaseline";
    ModuleVersion = "1.0";
    ConfigurationName = "AzureOSBaseline";
};

Here's what it could look like in DSCv3:

name: Disable SMB v1 server
type: Microsoft.DSC/Policy
properties:
  audit:
    resource:
      type: Microsoft.Windows/Registry
      properties:
        keyPath: HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
        valueName: SMB1
    expected:
      valueData:
          DWord: 0
    analyzeOperation: EqualsOrNotExist
  remediation:
    apply:
      _exist: false

In this example if the SMB1 property exists or doesn't equal 0, then the remediation is to delete it.

Proposed technical implementation details (optional)

No response

SteveL-MSFT commented 1 month ago

Thinking about this, it might make sense to simplify this by having the ability to inform dsc how to perform a test could be under a meta property:

name: Disable SMB v1 server
type: Microsoft.Windows/Registry
metadata:
  Microsoft.DSC:
    policy:
      testOperation: EqualsOrNotExist
      remediation:
        _exist: false
properties:
  keyPath: HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
  valueName: SMB1
  valueData:
    DWord: 0

I think I prefer this rather than adding another group type resource. Adapters would have to advertise they support the policy (or other name) capability.

michaeltlombardi commented 1 month ago

In this case, I think I disagree about group resource vs capability/metadata - this is a specific behavior to apply to other, existing resources for a specific model. I'm also not a huge fan of the remediation field in metadata/Microsoft.DSC/remediation - it splits cognition between reviewing the properties and the metadata to understand what the set operation will do.

On the other hand, I find the Microsoft.DSC/Policy[^1] resource to be very readable. I would make it slightly more explicit by requiring the remediation field to specify a resource instance (type and properties together) - I might use one resource for audit and another for remediation.

Maybe something like:

name: Disable SMB v1 server
type: Microsoft.DSC/Audit
properties:
  analyzeOperation: EqualsOrNotExist
  # resource sent as-is to `get`
  resource:
    type: Microsoft.Windows/Registry
    properties:
      keyPath:   HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
      valueName: SMB1
  # Audit resource only checks result of get against key-value pairs in expected
  expected:
    valueData: { DWord: 0 }
  # remediation sent as-is to set
  remediation:
    type: Microsoft.Windows/Registry
    properties:
      keyPath:   HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
      valueName: SMB1
      _exist:    false

With slightly more work on the resource side itself, the remediation field could be simplified for cases where you are using the same resource for set by merging the values:

name: Disable SMB v1 server
type: Microsoft.DSC/Audit
properties:
  analyzeOperation: EqualsOrNotExist
  # resource sent as-is to `get`
  resource:
    type: Microsoft.Windows/Registry
    properties:
      keyPath:   HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
      valueName: SMB1
  # Audit resource only checks result of get against key-value pairs in expected
  expected:
    valueData: { DWord: 0 }
  # remediation merged on top of resource to send to set - only specify type/etc if needed.
  remediation:
    properties:
      _exist:    false

It's also worth noting that regardless of what we do for this sort of resource, we can't get purely static analysis of either instance from the JSON schema, I don't think. We could maybe do it with some clever $ref to JSON pointers (the value of expected must always adhere to the schema of the resource defined by resource) but I think it very likely that this will require runtime validation - not a bad thing, but worth keeping in mind for editors and higher order tools.

[^1]: Recommend not naming this capability or resource in DSC policy to avoid conflation with DSC settings/policy as discussed in #282.