From 3fbebdf2b4d31ec555e898e74c43b4742f5bef77 Mon Sep 17 00:00:00 2001 From: Keshi Tan Date: Tue, 2 Jun 2020 04:41:39 +0800 Subject: [PATCH] fix(cli): Org policy fix for CFT Scorecard (#704) * fixing the way to handle org policy data * update user guide for windows * increment version * fixing the way to handle org policy data * update user guide for windows * rebase onto upstream master --- cli/Makefile | 2 +- cli/docs/scorecard.md | 6 ++++ cli/scorecard/cmd.go | 2 +- cli/scorecard/proto.go | 28 ++++++++++++++----- .../gcp_org_policy_skip_default_network.yaml | 11 ++++---- 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/cli/Makefile b/cli/Makefile index 4630ebf5be4..669a9c72cfd 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -1,7 +1,7 @@ SHELL := /bin/bash # Changing this value will trigger a new release -VERSION=v0.3.3 +VERSION=v0.3.4 BINARY=bin/cft GITHUB_REPO=github.com/GoogleCloudPlatform/cloud-foundation-toolkit PLATFORMS := linux windows darwin diff --git a/cli/docs/scorecard.md b/cli/docs/scorecard.md index c799cecbdce..4a1794ef958 100644 --- a/cli/docs/scorecard.md +++ b/cli/docs/scorecard.md @@ -45,6 +45,7 @@ This tutorial will walk you through setting up Scorecard for a single project. # could also use --folder or --organization ``` The alternative is to use [integrated inventory refresh feature](#Using-integrated-inventory-refresh-feature) `cft scorecard --refresh` + 7. Download the CFT CLI and make it executable: ``` # OS X @@ -53,7 +54,12 @@ This tutorial will walk you through setting up Scorecard for a single project. curl -o cft https://storage.googleapis.com/cft-cli/latest/cft-linux-amd64 # executable chmod +x cft + + # Windows + curl -o cft.exe https://storage.googleapis.com/cft-cli/latest/cft-windows-amd64 ``` +The user guide in rest of this document provides examples for Linux and OS X environment. For Windows, update file names and directory paths accordingly. + 8. Download the sample policy library and add a sample constraint for detecting public buckets: ``` git clone https://github.com/forseti-security/policy-library.git diff --git a/cli/scorecard/cmd.go b/cli/scorecard/cmd.go index e02a35e1594..4728f4b4330 100644 --- a/cli/scorecard/cmd.go +++ b/cli/scorecard/cmd.go @@ -64,7 +64,7 @@ var Cmd = &cobra.Command{ cft scorecard --policy-path /policy-library \ --stdin - As of now, CAI export file names need to be resource_inventory.json and iam_inventory.json + As of now, CAI export file names need to be: resource_inventory.json, iam_inventory.json, org_policy_inventory.json, access_policy_inventory.json `, Args: cobra.NoArgs, diff --git a/cli/scorecard/proto.go b/cli/scorecard/proto.go index d410117a639..e60cd3a2d94 100644 --- a/cli/scorecard/proto.go +++ b/cli/scorecard/proto.go @@ -25,17 +25,31 @@ import ( ) func unMarshallAsset(from []byte, to proto.Message) error { - umar := &jsonpb.Unmarshaler{AllowUnknownFields: true} - err := umar.Unmarshal(strings.NewReader(string(from)), to) - if err == nil { - return nil - } + // CAI export returns org_policy [1] with update_time if Timestamp format in Seconds and Nanos + // but in jsonpb, Timestamp is expected to be a string in the RFC 3339 format [2]. + // i.e. "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" + // Hence doing a workaround to remove the field so that jsonpb.Unmarshaler can handle org policy. + // [1] https://github.com/googleapis/googleapis/blob/master/google/cloud/orgpolicy/v1/orgpolicy.proto + // [2] https://godoc.org/google.golang.org/protobuf/types/known/timestamppb#Timestamp + + // Using json.Unmarshal will return no error + // but this approach will lose the "oneof" proto fields in org_policy and access_policy - err = json.Unmarshal(from, to) + var temp map[string]interface{} + err := json.Unmarshal(from, &temp) + if err != nil { + return errors.Wrap(err, "marshaling to interface") + } + if val, ok := temp["org_policy"]; ok { + for _, op := range val.([]interface{}) { + orgPolicy := op.(map[string]interface{}) + delete(orgPolicy, "update_time") + } + } + err = protoViaJSON(temp, to) if err == nil { return nil } - return err } diff --git a/cli/testdata/scorecard/policy-library/policies/templates/gcp_org_policy_skip_default_network.yaml b/cli/testdata/scorecard/policy-library/policies/templates/gcp_org_policy_skip_default_network.yaml index f63d32b53f4..eb485541e7c 100644 --- a/cli/testdata/scorecard/policy-library/policies/templates/gcp_org_policy_skip_default_network.yaml +++ b/cli/testdata/scorecard/policy-library/policies/templates/gcp_org_policy_skip_default_network.yaml @@ -57,11 +57,12 @@ spec: asset.asset_type == "cloudresourcemanager.googleapis.com/Organization" lib.has_field(asset, "org_policy") - constraint_item := asset.org_policy[_] - constraint_item.constraint == "constraints/compute.skipDefaultNetworkCreation" - boolean_policy := lib.get_default(constraint_item, "boolean_policy", {}) - enforced := lib.get_default(boolean_policy, "enforced", false) - enforced == false + constraint_item := asset.org_policy[_] + lib.has_field(constraint_item, "boolean_policy") + constraint_item.constraint == "constraints/compute.skipDefaultNetworkCreation" + boolean_policy := lib.get_default(constraint_item, "boolean_policy", {}) + enforced := lib.get_default(boolean_policy, "enforced", false) + enforced == false message := "Required enforcement of skipDefaultNetworkCreation at org level" metadata := {"resource": asset.name, "constraint_name": constraint_item.constraint}