Skip to content

Commit

Permalink
auto generate deployment policy (#939)
Browse files Browse the repository at this point in the history
  • Loading branch information
jhsinger-klotho authored Feb 28, 2024
1 parent 2dbc5bc commit 18cc396
Show file tree
Hide file tree
Showing 93 changed files with 5,927 additions and 13 deletions.
2 changes: 1 addition & 1 deletion create_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ fi
[ -e "$out_dir/dataflow-topology.yaml" ] && cp "$out_dir/dataflow-topology.yaml" "$test_dir/$name.dataflow-viz.yaml"
[ -e "$out_dir/iac-topology.yaml" ] && cp "$out_dir/iac-topology.yaml" "$test_dir/$name.iac-viz.yaml"
[ -e "$out_dir/error_details.json" ] && cp "$out_dir/error_details.json" "$test_dir/$name.err.json"

[ -e "$out_dir/deployment_permissions_policy.json" ] && cp "$out_dir/deployment_permissions_policy.json" "$test_dir/$name.deployment-policy.json"
rm -rf $out_dir
15 changes: 15 additions & 0 deletions pkg/engine/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
knowledgebase "github.com/klothoplatform/klotho/pkg/knowledgebase"
"github.com/klothoplatform/klotho/pkg/knowledgebase/reader"
"github.com/klothoplatform/klotho/pkg/logging"
"github.com/klothoplatform/klotho/pkg/provider/aws"
"github.com/klothoplatform/klotho/pkg/templates"
"github.com/pkg/errors"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -439,6 +440,20 @@ func (em *EngineMain) RunEngine(cmd *cobra.Command, args []string) (exitCode int
},
)

if architectureEngineCfg.provider == "aws" {
polictBytes, err := aws.DeploymentPermissionsPolicy(context.Solutions[0])
if err != nil {
internalError(fmt.Errorf("failed to generate deployment permissions policy: %w", err))
return
}
files = append(files,
&kio.RawFile{
FPath: "deployment_permissions_policy.json",
Content: polictBytes,
},
)
}

err = kio.OutputTo(files, architectureEngineCfg.outputDir)
if err != nil {
internalError(fmt.Errorf("failed to write output files: %w", err))
Expand Down
51 changes: 51 additions & 0 deletions pkg/engine/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

construct "github.com/klothoplatform/klotho/pkg/construct"
engine_errs "github.com/klothoplatform/klotho/pkg/engine/errors"
"github.com/klothoplatform/klotho/pkg/provider/aws"
"github.com/r3labs/diff"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -87,6 +88,21 @@ func (tc engineTestCase) Test(t *testing.T) {
// Run resulted in a failure. After checking the error details, we're done.
return
}

// Check to make sure that we produce a policy for deployment roles
deploymentPolicyBytes, err := aws.DeploymentPermissionsPolicy(context.Solutions[0])
if err != nil {
t.Fatal(fmt.Errorf("failed to generate deployment permissions policy: %w", err))
}
deploymentPolicyFile, err := os.Open(strings.Replace(tc.inputPath, ".input.yaml", ".deployment-policy.json", 1))
if err != nil && !os.IsNotExist(err) {
t.Fatal(fmt.Errorf("failed to open deployment policy file: %w", err))
}
if deploymentPolicyFile != nil {
defer deploymentPolicyFile.Close()
}
assertDeploymentPolicy(t, deploymentPolicyFile, deploymentPolicyBytes)

sol := context.Solutions[0]
actualContent, err := yaml.Marshal(construct.YamlGraph{Graph: sol.DataflowGraph()})
if err != nil {
Expand Down Expand Up @@ -179,6 +195,41 @@ func assertErrDetails(t *testing.T, expectR io.Reader, actual []engine_errs.Engi
assert.Equal(t, expectV, actualV, "error details")
}

func assertDeploymentPolicy(t *testing.T, expectR io.Reader, policyBytes []byte) {
var expect, actual map[string]interface{}
err := json.NewDecoder(expectR).Decode(&expect)
if err != nil {
t.Errorf("failed to read expected deployment policy: %v", err)
return
}
err = json.Unmarshal(policyBytes, &actual)
if err != nil {
t.Errorf("failed to unmarshal actual deployment policy: %v", err)
return
}
differ, err := diff.NewDiffer(diff.SliceOrdering(false))
if err != nil {
t.Errorf("failed to create differ for deployment policy: %v", err)
return
}
changes, err := differ.Diff(expect, actual)
if err != nil {
t.Errorf("failed to diff deployment policy: %v", err)
return
}
for _, c := range changes {
path := strings.Join(c.Path, ".")
switch c.Type {
case diff.CREATE:
t.Errorf("deployment policy %s %s: %v", c.Type, path, c.To)
case diff.DELETE:
t.Errorf("deployment policy %s %s: %v", c.Type, path, c.From)
case diff.UPDATE:
t.Errorf("deployment policy %s %s: %v to %v", c.Type, path, c.From, c.To)
}
}
}

func assertYamlMatches(t *testing.T, expectStr, actualStr string, name string) {
t.Helper()
var expect, actual map[string]interface{}
Expand Down
118 changes: 118 additions & 0 deletions pkg/engine/testdata/2_routes.deployment-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
{
"Statement": [
{
"Action": [
"apigateway:CreateStage",
"apigateway:DeleteStage",
"apigateway:UpdateStage"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateDeployment",
"apigateway:DeleteDeployment",
"apigateway:UpdateDeployment"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateRestApi",
"apigateway:DeleteRestApi",
"apigateway:UpdateRestApi"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateResource",
"apigateway:DeleteResource",
"apigateway:UpdateResource"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:PutMethod",
"apigateway:DeleteMethod",
"apigateway:UpdateMethod"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:PutIntegration",
"apigateway:DeleteIntegration",
"apigateway:UpdateIntegration"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"lambda:AddPermission",
"lambda:RemovePermission",
"lambda:AddPermission"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"lambda:CreateFunction",
"lambda:DeleteFunction",
"lambda:UpdateFunctionConfiguration"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"ecr:PutImage",
"ecr:BatchDeleteImage",
"ecr:PutImage"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:UpdateAssumeRolePolicy"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": null,
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"ecr:CreateRepository",
"ecr:DeleteRepository",
"ecr:PutLifecyclePolicy"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"logs:CreateLogGroup",
"logs:DeleteLogGroup",
"logs:PutRetentionPolicy"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
}
55 changes: 55 additions & 0 deletions pkg/engine/testdata/cf_distribution.deployment-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"Statement": [
{
"Action": null,
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateStage",
"apigateway:DeleteStage",
"apigateway:UpdateStage"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateDeployment",
"apigateway:DeleteDeployment",
"apigateway:UpdateDeployment"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:PutBucketPolicy",
"s3:DeleteBucketPolicy",
"s3:PutBucketPolicy"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateRestApi",
"apigateway:DeleteRestApi",
"apigateway:UpdateRestApi"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:CreateBucket",
"s3:DeleteBucket",
"s3:PutBucketAcl"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
}
109 changes: 109 additions & 0 deletions pkg/engine/testdata/delete_api_to_lambda_edge.deployment-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
{
"Statement": [
{
"Action": [
"apigateway:CreateStage",
"apigateway:DeleteStage",
"apigateway:UpdateStage"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"lambda:CreateFunction",
"lambda:DeleteFunction",
"lambda:UpdateFunctionConfiguration"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateDeployment",
"apigateway:DeleteDeployment",
"apigateway:UpdateDeployment"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": null,
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"ecr:PutImage",
"ecr:BatchDeleteImage",
"ecr:PutImage"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"iam:CreateRole",
"iam:DeleteRole",
"iam:UpdateAssumeRolePolicy"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateRestApi",
"apigateway:DeleteRestApi",
"apigateway:UpdateRestApi"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"ecr:CreateRepository",
"ecr:DeleteRepository",
"ecr:PutLifecyclePolicy"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"logs:CreateLogGroup",
"logs:DeleteLogGroup",
"logs:PutRetentionPolicy"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:CreateResource",
"apigateway:DeleteResource",
"apigateway:UpdateResource"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:PutMethod",
"apigateway:DeleteMethod",
"apigateway:UpdateMethod"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"apigateway:PutIntegration",
"apigateway:DeleteIntegration",
"apigateway:UpdateIntegration"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
}
Loading

0 comments on commit 18cc396

Please sign in to comment.