Skip to content

Commit

Permalink
Add coommand usage of C2P for Kyverno to readme
Browse files Browse the repository at this point in the history
Signed-off-by: Takumi Yanagawa <yana@jp.ibm.com>
  • Loading branch information
yana1205 committed Oct 31, 2023
1 parent dab6c3d commit 22bfe60
Show file tree
Hide file tree
Showing 13 changed files with 1,256 additions and 109 deletions.
97 changes: 95 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,103 @@
# compliance-to-policy
Compliance-to-Policy (C2P) provides the framework to bridge the gap between compliance and policy administration.
Compliance-to-Policy (C2P) provides the framework to bridge Compliance administration and Policy administration by [OSCAL](https://pages.nist.gov/OSCAL/). OSCAL (Open Security Controls Assessment Language) is a standardized framework developed by NIST for expressing and automating the assessment and management of security controls in machine-readable format (xml, json, yaml)

## C2P as pipeline task
## Continuous Compliance by C2P

https://github.com/IBM/compliance-to-policy/assets/113283236/da3518d0-53de-4bd6-8703-04ce94e9dfba

## Usage of C2P commands

### C2P for Kyverno
Prepare Kyverno Policy Resources
- You can use [policy-resources for test](/pkg/testdata/kyverno/policy-resources)
- You can load Kyverno Policy Resource from Kyverno Policies (https://github.com/kyverno/policies)
1. Run `kyverno tools load-policy-resources` command
```
$ go run cmd/c2pcli/main.go kyverno tools load-policy-resources --src https://github.com/kyverno/policies --dest /tmp/policies
```
```
$ tree /tmp/policies
/tmp/policies
├── add-apparmor-annotations
│ └── add-apparmor-annotations.yaml
├── add-capabilities
│ └── add-capabilities.yaml
├── add-castai-removal-disabled
│ └── add-castai-removal-disabled.yaml
├── add-certificates-volume
│ └── add-certificates-volume.yaml
├── add-default-resources
...
```
- You can check result.json about what resources are downloaded.
```
$ cat /tmp/policies/result.json

```
- There are some policies that depend on context. Please add the context resources manually. result.json contains list of the policies that have context field
```
$ jq -r .summary.resourcesHavingContext /tmp/policies/result.json
[
"allowed-podpriorities",
"allowed-base-images",
"advanced-restrict-image-registries",
...
"require-linkerd-server"
]
```
#### Convert OSCAL to Kyverno Policy
```
$ go run cmd/c2pcli/main.go kyverno oscal2policy -c ./pkg/testdata/kyverno/c2p-config.yaml -o /tmp/kyverno-policies
2023-10-31T07:23:56.291+0900 INFO kyverno/c2pcr kyverno/configparser.go:53 Component-definition is loaded from ./pkg/testdata/kyverno/component-definition.json
$ tree /tmp/kyverno-policies
/tmp/kyverno-policies
└── allowed-base-images
├── 02-setup-cm.yaml
└── allowed-base-images.yaml
```

#### Convert Policy Report to OSCAL Assessment Results
```
$ go run cmd/c2pcli/main.go kyverno result2oscal -c ./pkg/testdata/kyverno/c2p-config.yaml -o /tmp/assessment-results
$ tree /tmp/assessment-results
/tmp/assessment-results
└── assessment-results.json
```

Reformat in human friendly format (markdown file) since OSCAL is not machine friendly format.
```
$ go run cmd/c2pcli/main.go kyverno oscal2posture -c ./pkg/testdata/kyverno/c2p-config.yaml --assessment-results /tmp/assessment-results/assessment-results.json -o /tmp/compliance-report.md
```

```
$ head -n 15 /tmp/compliance-report.md
## Catalog
## Component: Kubernetes
#### Result of control: cm-8.3_smt.a
Rule ID: allowed-base-images
<details><summary>Details</summary>
- Subject UUID: 0b1adf1c-f6e2-46af-889e-39255e669655
- Title: ApiVersion: v1, Kind: Pod, Namespace: argocd, Name: argocd-application-controller-0
- Result: fail
- Reason:
```
validation failure: This container image&#39;s base is not in the approved list or is not specified. Only pre-approved base images may be used. Please contact the platform team for assistance.
```
```
### C2P for Open Cluster Management (OCM)
OCM has Policy Governance Framework, where the policy is OCM Policy and the PVP audit result is status of deployed OCM Policy.
#### Convert OSCAL Component Definition to OCM Policy
TBD
#### Convert OCM Policy Status to OSCAL Assessment Results
TBD
### Setup pipeline
1. Create two repositories (one is configuration repository that's used for pipeline from OSCAL to Policy and another is evidence repository that's used for pipeline from OCM statuses to Compliance result)
- For example, c2p-for-ocm-pipeline01-config and c2p-for-ocm-pipeline01-evidence
Expand Down
13 changes: 9 additions & 4 deletions cmd/kyverno/tools/subcommands/kyverno/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,24 @@ type Result struct {
}

func Run(options *Options) error {
srcDir, destDir := options.SourceDir, options.DestinationDir
srcUrl, destDir, tempDirPath := options.SourceUrl, options.DestinationDir, options.TempDirPath

if _, err := pkg.MakeDir(destDir); err != nil {
logger.Error(fmt.Sprintf("Failed to create a destination directory %s", destDir))
return err
}

fl := kyverno.NewFileLoader()

err := fl.LoadFromDirectory(srcDir)
gitUtils := pkg.NewGitUtils(pkg.NewTempDirectory(tempDirPath))
cloneDir, path, err := gitUtils.GitClone(srcUrl)
if err != nil {
return err
}
srcDir := cloneDir + "/" + path

fl := kyverno.NewFileLoader()
if err := fl.LoadFromDirectory(srcDir); err != nil {
return err
}

inverseMap := map[string][]*policyResourceIndex{}
policyResourceIndice := []policyResourceIndex{}
Expand Down
8 changes: 5 additions & 3 deletions cmd/kyverno/tools/subcommands/kyverno/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,27 @@ import (
)

type Options struct {
SourceDir string
SourceUrl string
DestinationDir string
TempDirPath string
}

func NewOptions() *Options {
return &Options{}
}

func (o *Options) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&o.SourceDir, "src", "", "path to a directory of Kyverno policy collection")
fs.StringVar(&o.SourceUrl, "src", "", "url or path to a directory of Kyverno policy collection")
fs.StringVar(&o.DestinationDir, "dest", "", "path to a directory for output retrieved Kyverno policies")
fs.StringVar(&o.TempDirPath, "temp-dir", "", "path to temp directory (default: system-defined temporary directory)")
}

func (o *Options) Complete() error {
return nil
}

func (o *Options) Validate() error {
if o.SourceDir == "" {
if o.SourceUrl == "" {
return errors.New("--src is required")
}
if o.DestinationDir == "" {
Expand Down
8 changes: 8 additions & 0 deletions pkg/testdata/kyverno/c2p-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
compliance:
name: Demo Compliance
componentDefinition:
url: ./pkg/testdata/kyverno/component-definition.json
policyResources:
url: ./pkg/testdata/kyverno/policy-resources
policyResults:
url: ./pkg/testdata/kyverno/policy-reports
12 changes: 6 additions & 6 deletions pkg/testdata/kyverno/component-definition.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
{
"name": "Rule_Id",
"ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/kubernetes",
"value": "advanced-restrict-image-registries",
"value": "allowed-base-images",
"remarks": "rule_set_0"
},
{
"name": "Rule_Description",
"ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/kubernetes",
"value": "In instances where a ClusterPolicy defines all the approved image registries is insufficient, more granular control may be needed to set permitted registries, especially in multi-tenant use cases where some registries may be based on the Namespace. This policy shows an advanced version of the Restrict Image Registries policy which gets a global approved registry from a ConfigMap and, based upon an annotation at the Namespace level, gets the registry approved for that Namespace.",
"value": "Building images which specify a base as their origin is a good start to improving supply chain security, but over time organizations may want to build an allow list of specific base images which are allowed to be used when constructing containers. This policy ensures that a container's base, found in an OCI annotation, is in a cluster-wide allow list.",
"remarks": "rule_set_0"
}
],
Expand All @@ -46,7 +46,7 @@
{
"name": "Rule_Id",
"ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/kubernetes",
"value": "advanced-restrict-image-registries"
"value": "allowed-base-images"
}
]
}
Expand All @@ -65,19 +65,19 @@
{
"name": "Rule_Id",
"ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/kyverno",
"value": "advanced-restrict-image-registries",
"value": "allowed-base-images",
"remarks": "rule_set_1"
},
{
"name": "Check_Id",
"ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/kyverno",
"value": "advanced-restrict-image-registries",
"value": "allowed-base-images",
"remarks": "rule_set_1"
},
{
"name": "Check_Description",
"ns": "http://ibm.github.io/compliance-trestle/schemas/oscal/cd/kyverno",
"value": "advanced-restrict-image-registries",
"value": "allowed-base-images",
"remarks": "rule_set_1"
}
],
Expand Down
174 changes: 174 additions & 0 deletions pkg/testdata/kyverno/policy-reports/clusterpolicies.kyverno.io.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
apiVersion: v1
items:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
annotations:
kyverno.io/kubernetes-version: "1.23"
kyverno.io/kyverno-version: 1.7.0
policies.kyverno.io/category: Other
policies.kyverno.io/description: Building images which specify a base as their
origin is a good start to improving supply chain security, but over time organizations
may want to build an allow list of specific base images which are allowed
to be used when constructing containers. This policy ensures that a container's
base, found in an OCI annotation, is in a cluster-wide allow list.
policies.kyverno.io/minversion: 1.7.0
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/title: Allowed Base Images
creationTimestamp: "2023-10-18T05:41:05Z"
generation: 1
labels:
app.kubernetes.io/instance: c2p
name: allowed-base-images
resourceVersion: "55817"
uid: 2fe80492-772f-424e-a259-1b5b43f74005
spec:
background: true
rules:
- context:
- configMap:
name: baseimages
namespace: platform
name: baseimages
match:
any:
- resources:
kinds:
- Pod
name: allowed-base-images
preconditions:
all:
- key: '{{request.operation || ''BACKGROUND''}}'
operator: NotEquals
value: DELETE
validate:
foreach:
- context:
- imageRegistry:
reference: '{{ element.image }}'
name: imageData
- name: basename
variable:
default: ""
jmesPath: imageData.manifest.annotations."org.opencontainers.image.base.name"
deny:
conditions:
all:
- key: '{{ basename }}'
operator: AnyNotIn
value: '{{ baseimages.data.allowedbaseimages }}'
list: request.object.spec.containers
message: This container image's base is not in the approved list or is not
specified. Only pre-approved base images may be used. Please contact the
platform team for assistance.
validationFailureAction: audit
status:
autogen:
rules:
- context:
- configMap:
name: baseimages
namespace: platform
name: baseimages
exclude:
resources: {}
generate:
clone: {}
cloneList: {}
match:
any:
- resources:
kinds:
- DaemonSet
- Deployment
- Job
- StatefulSet
- ReplicaSet
- ReplicationController
resources: {}
mutate: {}
name: autogen-allowed-base-images
preconditions:
all:
- key: '{{request.operation || ''BACKGROUND''}}'
operator: NotEquals
value: DELETE
validate:
foreach:
- context:
- imageRegistry:
reference: '{{ element.image }}'
name: imageData
- name: basename
variable:
default: ""
jmesPath: imageData.manifest.annotations."org.opencontainers.image.base.name"
deny:
conditions:
all:
- key: '{{ basename }}'
operator: AnyNotIn
value: '{{ baseimages.data.allowedbaseimages }}'
list: request.object.spec.template.spec.containers
message: This container image's base is not in the approved list or is not
specified. Only pre-approved base images may be used. Please contact the
platform team for assistance.
- context:
- configMap:
name: baseimages
namespace: platform
name: baseimages
exclude:
resources: {}
generate:
clone: {}
cloneList: {}
match:
any:
- resources:
kinds:
- CronJob
resources: {}
mutate: {}
name: autogen-cronjob-allowed-base-images
preconditions:
all:
- key: '{{request.operation || ''BACKGROUND''}}'
operator: NotEquals
value: DELETE
validate:
foreach:
- context:
- imageRegistry:
reference: '{{ element.image }}'
name: imageData
- name: basename
variable:
default: ""
jmesPath: imageData.manifest.annotations."org.opencontainers.image.base.name"
deny:
conditions:
all:
- key: '{{ basename }}'
operator: AnyNotIn
value: '{{ baseimages.data.allowedbaseimages }}'
list: request.object.spec.jobTemplate.spec.template.spec.containers
message: This container image's base is not in the approved list or is not
specified. Only pre-approved base images may be used. Please contact the
platform team for assistance.
conditions:
- lastTransitionTime: "2023-10-18T05:53:47Z"
message: Ready
reason: Succeeded
status: "True"
type: Ready
ready: true
rulecount:
generate: 0
mutate: 0
validate: 1
verifyimages: 0
kind: List
metadata:
resourceVersion: ""
Loading

0 comments on commit 22bfe60

Please sign in to comment.