Skip to content

Commit

Permalink
feat: make this repo a go pkg
Browse files Browse the repository at this point in the history
1. utilities for managing and rendering:
  - aws policies
  - cloudformation templates
2. centralized policy actions/permissions
  • Loading branch information
fidiego committed Oct 2, 2024
1 parent 1a756a7 commit fe4574d
Show file tree
Hide file tree
Showing 35 changed files with 1,632 additions and 3 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

Terraform projects that make it easy to use the Nuon managed sandboxes.

Each of our sandboxes is published as a Terraform module. In order to use one, you would need to create a Terraform project that imports the sandbox you want to use, and sets up the required providers and S3 backend. To save you the hassle, this repo provides a ready-to-use Terraform project for each sandbox that we manage.
Each of our sandboxes is published as a Terraform module. In order to use one,
you would need to create a Terraform project that imports the sandbox you want
to use, and sets up the required providers and S3 backend. To save you the
hassle, this repo provides a ready-to-use Terraform project for each sandbox
that we manage.

## Using a Sandbox

To use one of our managed sandboxes without additional setup, simply add a sandbox config to your app that references this repo. For example, to use the `aws-eks` sandbox:
To use one of our managed sandboxes without additional setup, simply add a
sandbox config to your app that references this repo. For example, to use the
`aws-eks` sandbox:

```hcl
resource "nuon_app_sandbox" "main" {
Expand All @@ -21,7 +27,8 @@ resource "nuon_app_sandbox" "main" {
}
```

The `branch` attribute will accept any valid Git ref, including a commit sha or tag.
The `branch` attribute will accept any valid Git ref, including a commit sha or
tag.

Reference the documentation for each sandbox module for detailed usage examples.

Expand Down
33 changes: 33 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module github.com/nuonco/sandboxes

go 1.22.4

require (
github.com/go-faker/faker/v4 v4.5.0
github.com/go-playground/validator/v10 v10.22.1
github.com/mitchellh/mapstructure v1.5.0
github.com/stretchr/testify v1.9.0
google.golang.org/protobuf v1.34.2
)

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
55 changes: 55 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/go-faker/faker/v4 v4.5.0/go.mod h1:p3oq1GRjG2PZ7yqeFFfQI20Xm61DoBDlCA8RiSyZ48M=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
22 changes: 22 additions & 0 deletions pkg/sandboxes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Sandboxes

Common parsing logic / types for sandboxes and their outputs.

## Background

We export outputs from our sandboxes and need to use _some_ values in code. For
instance, to look up an ECR repo, deploy a runner etc. We tried to avoid
managing types for these, but ultimately it led to too many places where output
logic was leaking / dependencies were not known.

This package enforces that we model the outputs from our sandboxes as actual go
types, so we can safely rely on them throughout our code.

Additionally, it provides a convenient location for the management of
permissions with the added benefit of making them available as code. We make use
of this by using this pkg to generate the role policy json files and yaml
templates.

## Notes

This code has been moved into this repo from the mono repo.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# generated on: {{ .GeneratedOn }}
Parameters:
RoleName:
Type: String
Default: "nuon-aws-ecs-byovpc-install-access"
Description: "Enter a name for the install role"
DelegationRoleARN:
Type: String
Default: ""
Description: "ARN for the role that will be assumed by roles in the trust policy."

Outputs:
RoleARN:
Description: IAM Role ARN
Value: !GetAtt InstallRole.Arn

Resources:

InstallRole:
Type: AWS::IAM::Role
Properties:
RoleName:
Ref: RoleName
Tags:
- Key: "managed-by"
Value: "nuon"
- Key: "nuon-sandbox-type"
Value: "aws-ecs-byovpc"
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
AWS: !Ref DelegationRoleARN

ProvisionPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub
- nuon-provision-${RoleName}
- RoleName: !Ref RoleName
Roles:
- !Ref InstallRole
PolicyDocument:
Statement:
- Effect: Allow
Resource: "*"
Action: {{ range .ProvisionPolicyPermissions }}
- {{ . }}{{ end }}

DeprovisionPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub
- nuon-deprovision-${RoleName}
- RoleName: !Ref RoleName
Roles:
- !Ref InstallRole
PolicyDocument:
Statement:
- Effect: Allow
Resource: "*"
Action: {{ range .DeprovisionPolicyPermissions }}
- {{ . }}{{ end }}
57 changes: 57 additions & 0 deletions pkg/sandboxes/aws-ecs-byovpc/cloudformation-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# generated on: {{ .GeneratedOn }}
Parameters:
RoleName:
Type: String
Default: "nuon-aws-ecs-byovpc-install-access"
Description: "Enter a name for the install role"

Outputs:
RoleARN:
Description: IAM Role ARN
Value: !GetAtt InstallRole.Arn

Resources:

InstallRole:
Type: AWS::IAM::Role
Properties:
RoleName:
Ref: RoleName
Tags:
- Key: "managed-by"
Value: "nuon"
- Key: "nuon-sandbox-type"
Value: "aws-ecs-byovpc"
AssumeRolePolicyDocument:
Statement:
{{ .TrustPolicy | indent 10 }}

ProvisionPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub
- nuon-provision-${RoleName}
- RoleName: !Ref RoleName
Roles:
- !Ref InstallRole
PolicyDocument:
Statement:
- Effect: Allow
Resource: "*"
Action: {{ range .ProvisionPolicyPermissions }}
- {{ . }}{{ end }}

DeprovisionPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub
- nuon-deprovision-${RoleName}
- RoleName: !Ref RoleName
Roles:
- !Ref InstallRole
PolicyDocument:
Statement:
- Effect: Allow
Resource: "*"
Action: {{ range .DeprovisionPolicyPermissions }}
- {{ . }}{{ end }}
20 changes: 20 additions & 0 deletions pkg/sandboxes/aws-ecs-byovpc/cloudformation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package awsecsbyovpc

import (
_ "embed"

cft "github.com/nuonco/sandboxes/pkg/sandboxes/cloudformation"
)

//go:embed cloudformation-template.yaml
var cloudformationTemplate string

//go:embed cloudformation-template-delegation.yaml
var cloudformationDelegationTemplate string

var CloudformationTemplates = cft.New(
cloudformationTemplate,
cloudformationDelegationTemplate,
ProvisionPermissions,
DeprovisionPermissions,
)
44 changes: 44 additions & 0 deletions pkg/sandboxes/aws-ecs-byovpc/iam.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package awsecsbyovpc

import perms "github.com/nuonco/sandboxes/pkg/sandboxes/permissions"

// provision role permissions specific to this sandbox
var ProvisionPermissions = append([]string{
"ecs:CreateCapacityProvider",
"ecs:CreateCluster",
"ecs:DescribeCapacityProviders",
"ecs:DescribeClusters",
"ecs:ListTagsForResource",
"ecs:PutClusterCapacityProviders",
"ecs:TagResource",
}, perms.BaseProvisionPermissions...)

// Full provision rol policy for this sandbox
var ProvisionPolicy = perms.Policy{
Version: "2012-10-17",
Statement: []perms.Statement{
{
Effect: "Allow",
Resource: "*",
Action: ProvisionPermissions,
},
},
}

// deprovision role permissions specific to this sandbox
var DeprovisionPermissions = append([]string{
"ecs:DeleteCapacityProvider",
"ecs:DeleteCluster",
}, perms.BaseDeprovisionPermissions...)

// Full deprovision role policy for this sandbox
var DeprovisionPolicy = perms.Policy{
Version: "2012-10-17",
Statement: []perms.Statement{
{
Effect: "Allow",
Resource: "*",
Action: DeprovisionPermissions,
},
},
}
59 changes: 59 additions & 0 deletions pkg/sandboxes/aws-ecs-byovpc/outputs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package awsecsbyovpc

import (
"fmt"

"github.com/go-playground/validator/v10"
"github.com/mitchellh/mapstructure"
"github.com/nuonco/sandboxes/pkg/sandboxes"
"google.golang.org/protobuf/types/known/structpb"
)

type ECSClusterOutputs struct {
ARN string `mapstructure:"arn"`
Name string `mapstructure:"name"`
ID string `mapstructure:"id"`
}

type RunnerOutputs struct {
// eks outputs
DefaultIAMRoleARN string `mapstructure:"default_iam_role_arn"`

// ecs runner outputs
Type string `mapstructure:"type"`
RunnerIAMRoleARN string `mapstructure:"runner_iam_role_arn"`
ODRIAMRoleARN string `mapstructure:"odr_iam_role_arn"`
InstallIAMRoleARN string `mapstructure:"install_iam_role_arn"`
}

type TerraformOutputs struct {
// domain outputs
PublicDomain sandboxes.DomainOutputs `mapstructure:"public_domain"`
InternalDomain sandboxes.DomainOutputs `mapstructure:"internal_domain"`

ECSCluster ECSClusterOutputs `mapstructure:"ecs_cluster"`
ECR sandboxes.ECROutputs `mapstructure:"ecr"`
VPC sandboxes.VPCOutputs `mapstructure:"vpc"`
Runner RunnerOutputs `mapstructure:"runner"`
}

func (t *TerraformOutputs) Validate() error {
validate := validator.New()
return validate.Struct(t)
}

func ParseTerraformOutputs(outputs *structpb.Struct) (TerraformOutputs, error) {
m := outputs.AsMap()

var tfOutputs TerraformOutputs
if err := mapstructure.Decode(m, &tfOutputs); err != nil {
return tfOutputs, fmt.Errorf("invalid terraform outputs: %w", err)
}

err := tfOutputs.Validate()
if err != nil {
return tfOutputs, fmt.Errorf("terraform output error: %w", err)
}

return tfOutputs, nil
}
Loading

0 comments on commit fe4574d

Please sign in to comment.