C2P
)Compliance-to-Policy (C2P) is designed to bridge Compliance as Code such as Open Security Controls Assessment Language (OSCAL) and Policy as Code used by Policy Validation Point (PVP). It generates policies in native format of PVP from OSCAL Component Definitions and produces OSCAL Assessment Results from the native assessment results of PVP. C2P can be used both as a command-line tool and a Python library, making it easy and flexible to integrate into your Continuous Compliance pipelines, such as GitHub Actions, Tekton Pipelines, or Agile Authoring Pipelines. It supports multiple PVP engines, including Kyverno, Open Cluster Management Policy Framework, and the open-source Auditree, through dedicated plugins for each. Custom plugins can be implemented with a small amount of Python code.
Demo:
Provide seamless integration with compliance frameworks and existing policy engines, and enable to use heterogeneous policy engines in compliance check operation
Roadmap:
The Go verion is available in the go directory.
pip install git+https://github.com/oscal-compass/compliance-to-policy.git
You may be asked passphrase of SSH key to access to the git repo.
git clone https://github.com/oscal-compass/compliance-to-policy.git
compliance-to-policy
cd compliance-to-policy
make install
Generate Kyverno Policy (C2P Compliance to Policy)
python samples_public/kyverno/compliance_to_policy.py -o /tmp/deliverable-policy
E.g.
$ python samples_public/kyverno/compliance_to_policy.py -o /tmp/deliverable-policy
tree /tmp/deliverable-policy
disallow-capabilities
- disallow-capabilities.yaml
allowed-base-images
- 02-setup-cm.yaml
- allowed-base-images.yaml
kubectl apply -R -f /tmp/deliverable-policy
E.g.
$ kubectl apply -R -f /tmp/deliverable-policy
namespace/platform created
configmap/baseimages created
Warning: Validation failure actions enforce/audit are deprecated, use Enforce/Audit instead.
clusterpolicy.kyverno.io/allowed-base-images created
clusterpolicy.kyverno.io/disallow-capabilities created
$ kubectl get policyreport,clusterpolicyreport -A
NAMESPACE NAME PASS FAIL WARN ERROR SKIP AGE
kube-system policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 12 0 0 0 19s
kube-system policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 9 2 0 0 0 19s
kyverno policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 18 0 0 0 9s
kyverno policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 18 0 0 0 0 9s
local-path-storage policyreport.wgpolicyk8s.io/cpol-allowed-base-images 0 3 0 0 0 16s
local-path-storage policyreport.wgpolicyk8s.io/cpol-disallow-capabilities 3 0 0 0 0 16s
kubectl get policyreport -A -o yaml > /tmp/policyreports.wgpolicyk8s.io.yaml
kubectl get clusterpolicyreport -o yaml > /tmp/clusterpolicyreports.wgpolicyk8s.io.yaml
python samples_public/kyverno/result_to_compliance.py \
-polr /tmp/policyreports.wgpolicyk8s.io.yaml \
-cpolr /tmp/clusterpolicyreports.wgpolicyk8s.io.yaml \
> /tmp/assessment_results.json
c2p tools viewer -ar /tmp/assessment_results.json -cdef ./plugins_public/tests/data/kyverno/component-definition.json -o /tmp/assessment_results.md
C2PConfig
object to supply compliance requirements and some metadata (See also kyverno/compliance_to_policy.py for a real example)
c2p_config = C2PConfig()
c2p_config.compliance = ComplianceOscal()
c2p_config.compliance.component_definition = 'plugins_public/tests/data/kyverno/component-definition.json'
c2p_config.pvp_name = 'Kyverno'
c2p_config.result_title = 'Kyverno Assessment Results'
c2p_config.result_description = 'OSCAL Assessment Results from Kyverno'
PluginKyverno
, PluginOCM
) and create PluginConfig
object to supply plugin specific properties
from plugins_public.plugins.kyverno import PluginConfigKyverno, PluginKyverno
policy_template_dir = 'plugins_public/tests/data/kyverno/policy-resources'
config = PluginConfigKyverno(policy_template_dir=policy_template_dir, deliverable_policy_dir='/tmp/deliverable-policies')
C2P
and Plugin
c2p = C2P(c2p_config)
plugin = PluginKyverno(config)
c2p
and generate PVP policy by generate_pvp_policy()
policy = c2p.get_policy()
plugin.generate_pvp_policy(policy)
$ tree /tmp/deliverable-policy
/tmp/deliverable-policy
├── allowed-base-images
│ ├── 02-setup-cm.yaml
│ └── allowed-base-images.yaml
└── disallow-capabilities
└── disallow-capabilities.yaml
C2PConfig
object to supply compliance requirements and some metadata (See also kyverno/compliance_to_policy.py for a real example)
c2p_config = C2PConfig()
c2p_config.compliance = ComplianceOscal()
c2p_config.compliance.component_definition = 'plugins_public/tests/data/kyverno/component-definition.json'
c2p_config.pvp_name = 'Kyverno'
c2p_config.result_title = 'Kyverno Assessment Results'
c2p_config.result_description = 'OSCAL Assessment Results from Kyverno'
PluginKyverno
, PluginOCM
) and create PluginConfig
object to supply plugin specific properties
from plugins_public.plugins.kyverno import PluginConfigKyverno, PluginKyverno
config = PluginConfigKyverno()
C2P
and Plugin
c2p = C2P(c2p_config)
plugin = PluginKyverno(config)
policy_report_file = 'plugins_public/tests/data/kyverno/policyreports.wgpolicyk8s.io.yaml'
cluster_policy_report_file = 'plugins_public/tests/data/kyverno/clusterpolicyreports.wgpolicyk8s.io.yaml'
policy_report = yaml.safe_load(pathlib.Path(policy_report_file).open('r'))
cluster_policy = yaml.safe_load(pathlib.Path(cluster_policy_report_file).open('r'))
pvp_raw_result = RawResult(data=policy_report['items'] + cluster_policy['items'])
generate_pvp_result()
of the plugin to get a formatted PVP result
pvp_result = PluginKyverno().generate_pvp_result(pvp_raw_result)
C2P
and call result_to_oscal()
to obtain Compliance Assessment Results
c2p.set_pvp_result(pvp_result)
oscal_assessment_results = c2p.result_to_oscal()
print(oscal_assessment_results.oscal_serialize_json(pretty=True))
c2p tools viewer -ar <OSCAL Assessment Results (json)> -cdef ./plugins_public/tests/data/ocm/component-definition.json -o /tmp/assessment_results.md
You can create a custom plugin by overriding PluginSpec
and PluginConfig
.
PluginSpec
has two interfaces generate_pvp_policy
and generate_pvp_result
.
C2P framework will instantiate PluginSpec
with PluginConfig
.
from c2p.framework.plugin_spec import PluginSpec
class YourPluginConfig(PluginConfig):
custom_field: str = Field(..., title='Custom field for your plugin')
class YourPlugin(PluginSpec):
def __init__(self, config: Optional[YourPluginConfig] = None) -> None:
super().__init__()
self.config = config # work on config
generate_pvp_policy()
in PluginSpec
accepts one argument policy: c2p.framework.models.Policy
.
The object has two fields (rule_sets
and parameters
). rule_sets
and parameters
are a list of Rule_Id, Check_Id, Parameter_Id, Parameter_Value, etc of the components handled by your PVP in OSCAL Component Definition. def generate_pvp_policy(self, policy: Policy):
rule_sets: List[RuleSet] = policy.rule_sets
parameters: List[Parameter] = policy.parameters
# generate deliverable policy from rule_sets and parameters
generate_pvp_result()
is expected to generate the summarized raw results of your PVP per unit in PVPResult
format. This unit must be associated with a unique id called Check_Id. For example of PluginKyverno, Policy Reports is the raw results and are summarized by policy name.
def generate_pvp_result(self, raw_result: RawResult) -> PVPResult:
pvp_result: PVPResult = PVPResult()
observations: List[ObservationByCheck] = []
polrs = list(
filter(
lambda x: x['apiVersion'] == 'wgpolicyk8s.io/v1alpha2' and x['kind'] == 'PolicyReport', raw_result.data
)
)
cpolrs = list(
filter(
lambda x: x['apiVersion'] == 'wgpolicyk8s.io/v1alpha2' and x['kind'] == 'ClusterPolicyReport',
raw_result.data,
)
)
results = []
for polr in polrs:
for result in polr['results']:
results.append(result)
for cpolr in cpolrs:
for result in cpolr['results']:
results.append(result)
policy_names = list(map(lambda x: x['policy'], results)) # policy_name is used as check_id
policy_names = set(policy_names)
for policy_name in policy_names:
observation = ObservationByCheck(check_id=policy_name, methods=['AUTOMATED'], collected=get_datetime())
The input argument raw_result
has data
field that is serialized raw results as dict. You can define your preferable format of the data. C2P Framework will pass PVP native results to plugin with this format.
$ python --version
Python 3.10.12
python -m venv .venv
make install-dev
pre-commit install
$ make test
plugins_public/tests/plugins/test_kyverno.py::test_kyverno_pvp_result_to_compliance PASSED [ 25%]
plugins_public/tests/plugins/test_kyverno.py::test_kyverno_compliance_to_policy PASSED [ 50%]
plugins_public/tests/plugins/test_ocm.py::test_ocm_pvp_result_to_compliance PASSED [ 75%]
plugins_public/tests/plugins/test_ocm.py::test_ocm_compliance_to_policy
------------------------------------------------------------------------------------------ live log call -------------------------------------------------------------------------------------------
2024-04-25 05:31:48 [ INFO] The deliverable policy directory '/var/folders/yx/1mv5rdh53xd93bphsc459ht00000gn/T/tmpxtvpcrpr/deliverable-policy' is not found. Creating... (ocm.py:191)
PASSED [100%]
======================================================================================== 4 passed in 0.31s =========================================================================================
tests/c2p/framework/test_c2p.py::test_result_to_oscal PASSED [ 33%]
tests/c2p/test_cli.py::test_run PASSED [ 66%]
tests/c2p/test_cli.py::test_version PASSED [100%]
======================================================================================== 3 passed in 0.26s =========================================================================================
make clean
If you would like to see the detailed LICENSE click here. Consult contributors for a list of authors and maintainers for the core team.
# Copyright (c) 2024 The OSCAL Compass Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
We are a Cloud Native Computing Foundation sandbox project.
The Linux Foundation® (TLF) has registered trademarks and uses trademarks. For a list of TLF trademarks, see Trademark Usage".
Compliance to Policy was originally created by IBM.