JeremiahSecrist / regula-nix

This project aims to help implement and enforce various security standards in NixOS. Regula meaning standards in latin.
https://jeremiahsecrist.github.io/regula-nix/
MIT License
12 stars 1 forks source link

Discuss structure of assertions for module system #1

Closed JeremiahSecrist closed 1 month ago

JeremiahSecrist commented 1 year ago

Problem Statement

As this project has a wide range of expected security benchmarks it is important that we define a nix module structure robust enough to support them.

Target Features:

JeremiahSecrist commented 1 year ago

So I've pondered over this for a bit and thought of the way in which this can be structured. first off we have rule itself, this rule with be given a generic name given a similar structure to the original nixos module system.

example:

regula.rules.fileSystems."/var" = {
  assertion = builtins.hasAttr "/var" config.fileSystems;
  message = "fileSystems.\"/var\" must have a unique mount point";
  testScript = ''
    mount | grep -E '\s/var\s'
  ''; # this is using for generating audit scripts for a given system and verify all assertions are working on the running system.
};

This enables it to be imported into another benchmark systems globally

regula.profiles.cis."server-1"."1.1.6" = {
  mode = 2; # range of 0-2 0 = disable 1 = warn 2 = assert 2 is default.
  rule = fileSystems."/var"; #  config.regula.rules would be the default base path.
  message = "CIS 1.1.6: ${config.regula.rules.fileSystems."/var".message}"; # can be made more dynamic in the future.
};

the idea here is that profiles inherit and expand upon rules in a meaningful way

JeremiahSecrist commented 1 year ago

another idea is to make profiles expect a attr of rules to import all rules and how to over write them

example:

regula.profiles.cis.server-1 = {
   message = "CIS ${link}:"
    rules = {
       "1.1.6" = filesystems."/var"
    };
};
JeremiahSecrist commented 1 year ago

two functions could describe these paradigms:

mkRuleOption = mkOption {
    type = attrsOf (submodule {
      options = {
        mode = mkOption {
          type = enum [0 1 2];
          default = 2;
        };
        assertion = mkOption {
          type = bool;
        };
        message = mkOption {
          type = string;
        };
      };
    });
  };
  mkProfileOption = mkOption {
    type = attrsOf (submodule {
      options = {
        rules = attrs;
        profileMessage = mkOption {
          type = string;
        };
      };
    });
  };
JeremiahSecrist commented 1 year ago

latest structure I am considering:

regula = {
    enable = true;
    settings = {
        activeProfiles = [
            config.regula.organizations.<orgName>.profiles.<profileName>
        ];
    };
    organizations = {
        <orgName> = {
            description = "";
            assertMessage = "";
            profiles = {
                <profileName-version> = {
                    description = "";
                    assertMessage = "";
                    importProfiles = [

                    ];
                    rules = [
                        config.regula.rules.<name>
                    ];
                    dissabledRules = [

                    ];
                    extraRules = [

                    ];
                };
            };
        };
    };
    rules = {
        "<name>" = {
            assetion = true;
            assertMessage = "should never show because is true";
            testScript = "";
        };
    };
};
Skarlett commented 1 year ago

lib.mkOverridable can be used to aquire .override

If undesirable to append .override, builtins.foldl (s: x: { } // x) can be used else where to achieve the same goal.

JeremiahSecrist commented 1 year ago

lib.mkOverridable can be used to aquire .override

If undesirable to append .override, builtins.foldl (s: x: { } // x) can be used else where to achieve the same goal.

This will be useful! As I want rules to be overrideable.