Skip to content

Commit

Permalink
Added Resource imports for Terraform (mondoohq#118)
Browse files Browse the repository at this point in the history
* feat: added import feature for some resources

Signed-off-by: Paul <[email protected]>

* feat: added azure resource terraform import

Signed-off-by: Paul <[email protected]>

* feat: added gcp/github/ms365 import

Signed-off-by: Paul <[email protected]>

* feat: added import for slack and ms365

Signed-off-by: Matthias Theuermann <[email protected]>

* fix: import errors and state import method

Signed-off-by: Matthias Theuermann <[email protected]>

* fix: updated docs

Signed-off-by: Matthias Theuermann <[email protected]>

* fix: removed unnecessary string conversion

Signed-off-by: Matthias Theuermann <[email protected]>

* fix: changed from basetype to types.StringPointerValue(nil) in import statement

Signed-off-by: Matthias Theuermann <[email protected]>

* feat: added custom-resources imports

Signed-off-by: Paul <[email protected]>

* fix: removed unused comments

Signed-off-by: Paul <[email protected]>

---------

Signed-off-by: Paul <[email protected]>
Signed-off-by: Matthias Theuermann <[email protected]>
Co-authored-by: Paul <[email protected]>
  • Loading branch information
mati007thm and Pauti authored Jul 15, 2024
1 parent 7233095 commit 358c827
Show file tree
Hide file tree
Showing 16 changed files with 399 additions and 28 deletions.
2 changes: 1 addition & 1 deletion docs/resources/integration_aws.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ variable "aws_access_key" {
}
variable "aws_secret_key" {
description = "AWS access key"
description = "AWS secret key"
type = string
}
Expand Down
3 changes: 1 addition & 2 deletions examples/resources/mondoo_integration_aws/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ variable "aws_access_key" {
}

variable "aws_secret_key" {
description = "AWS access key"
description = "AWS secret key"
type = string
}

Expand All @@ -33,4 +33,3 @@ resource "mondoo_integration_aws" "name" {
}
}
}

7 changes: 2 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ require (
github.com/hashicorp/terraform-plugin-go v0.23.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.8.0
github.com/stretchr/testify v1.9.0
go.mondoo.com/mondoo-go v0.0.0-20240611114249-2c3b9b20e67a
gopkg.in/yaml.v2 v2.4.0
)

require (
Expand All @@ -34,7 +34,6 @@ require (
github.com/cli/safeexec v1.0.1 // indirect
github.com/cli/shurcooL-graphql v0.0.4 // indirect
github.com/cloudflare/circl v1.3.8 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
Expand Down Expand Up @@ -91,7 +90,6 @@ require (
github.com/muesli/termenv v0.15.2 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/posener/complete v1.2.3 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/samber/lo v1.39.0 // indirect
Expand Down Expand Up @@ -123,7 +121,6 @@ require (
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.34.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -686,8 +686,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4=
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
23 changes: 21 additions & 2 deletions internal/provider/custom_compliance_framework_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"context"
"fmt"
"os"
"strings"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
Expand Down Expand Up @@ -217,5 +217,24 @@ func (r *customComplianceFrameworkResource) Delete(ctx context.Context, req reso
}

func (r *customComplianceFrameworkResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("mrn"), req, resp)
// resource.ImportStatePassthroughID(ctx, path.Root("mrn"), req, resp)
mrn := req.ID
splitMrn := strings.Split(mrn, "/")
spaceMrn := spacePrefix + splitMrn[len(splitMrn)-3]
spaceId := splitMrn[len(splitMrn)-3]
uid := splitMrn[len(splitMrn)-1]

framework, err := r.client.GetFramework(ctx, spaceMrn, spaceId, uid)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get Compliance Framework, got error: %s", err))
return
}

model := customComplianceFrameworkResourceModel{
Mrn: types.StringValue(string(framework.Mrn)),
DataUrl: types.StringPointerValue(nil),
SpaceId: types.StringValue(spaceId),
}

resp.State.Set(ctx, &model)
}
37 changes: 37 additions & 0 deletions internal/provider/custom_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"hash/crc32"
"os"
"strings"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
Expand Down Expand Up @@ -296,3 +297,39 @@ func (r *customPolicyResource) Delete(ctx context.Context, req resource.DeleteRe
}
}
}

func (r *customPolicyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
mrn := req.ID
splitMrn := strings.Split(mrn, "/")
spaceMrn := spacePrefix + splitMrn[len(splitMrn)-3]
spaceId := splitMrn[len(splitMrn)-3]

policy, err := r.client.GetPolicy(ctx, mrn, spaceMrn)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get policy, got error: %s", err))
return
}

content, err := r.client.DownloadBundle(ctx, string(policy.Mrn))
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to download bundle, got error: %s", err))
return
}

mrns, _ := types.ListValueFrom(ctx, types.StringType, []string{mrn})

model := customPolicyResourceModel{
SpaceId: types.StringValue(spaceId),
Mrns: mrns,
Overwrite: types.BoolValue(false),
Source: types.StringPointerValue(nil),
Content: types.StringValue(content),
Crc32Checksum: types.StringPointerValue(nil),
}

checksum := newCrc32Checksum([]byte(content))

model.Crc32Checksum = types.StringValue(checksum)

resp.State.Set(ctx, &model)
}
37 changes: 37 additions & 0 deletions internal/provider/custom_querypack.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"os"
"strings"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
Expand Down Expand Up @@ -288,3 +289,39 @@ func (r *customQueryPackResource) Delete(ctx context.Context, req resource.Delet
}
}
}

func (r *customQueryPackResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
mrn := req.ID
splitMrn := strings.Split(mrn, "/")
spaceMrn := spacePrefix + splitMrn[len(splitMrn)-3]
spaceId := splitMrn[len(splitMrn)-3]

queryPack, err := r.client.GetPolicy(ctx, mrn, spaceMrn)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get policy, got error: %s", err))
return
}

content, err := r.client.DownloadBundle(ctx, string(queryPack.Mrn))
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to download bundle, got error: %s", err))
return
}

mrns, _ := types.ListValueFrom(ctx, types.StringType, []string{mrn})

model := customQueryPackResourceModel{
SpaceId: types.StringValue(spaceId),
Mrns: mrns,
Overwrite: types.BoolValue(false),
Source: types.StringPointerValue(nil),
Content: types.StringValue(content),
Crc32Checksum: types.StringPointerValue(nil),
}

checksum := newCrc32Checksum([]byte(content))

model.Crc32Checksum = types.StringValue(checksum)

resp.State.Set(ctx, &model)
}
124 changes: 124 additions & 0 deletions internal/provider/gql.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ type Policy struct {
IsPublic mondoov1.Boolean
CreatedAt mondoov1.String
UpdatedAt mondoov1.String
Docs mondoov1.String
}

type PolicyNode struct {
Expand Down Expand Up @@ -250,6 +251,28 @@ type ContentPayload struct {
Content Content
}

func (c *ExtendedGqlClient) DownloadBundle(ctx context.Context, policyMrn string) (string, error) {
var q struct {
DownloadBundle struct {
PolicyBundleYaml struct {
Yaml string `graphql:"yaml"`
} `graphql:"... on PolicyBundleYaml"`
} `graphql:"downloadBundle(input: $input)"`
}
variables := map[string]interface{}{
"input": mondoov1.DownloadBundleInput{
Mrn: mondoov1.String(policyMrn),
},
}

err := c.Query(ctx, &q, variables)
if err != nil {
return "", err
}

return q.DownloadBundle.PolicyBundleYaml.Yaml, nil
}

func (c *ExtendedGqlClient) GetPolicies(ctx context.Context, scopeMrn string, catalogType string, assignedOnly bool) (*[]Policy, error) {
// Define the query struct according to the provided query
var contentQuery struct {
Expand Down Expand Up @@ -284,6 +307,28 @@ func (c *ExtendedGqlClient) GetPolicies(ctx context.Context, scopeMrn string, ca
return &policies, nil
}

func (c *ExtendedGqlClient) GetPolicy(ctx context.Context, policyMrn string, spaceMrn string) (*Policy, error) {
var q struct {
Policy Policy `graphql:"policy(input: $input)"`
}

input := mondoov1.PolicyInput{
Mrn: mondoov1.NewStringPtr(mondoov1.String(policyMrn)),
SpaceMrn: mondoov1.NewStringPtr(mondoov1.String(spaceMrn)),
}

variables := map[string]interface{}{
"input": input,
}

err := c.Query(ctx, &q, variables)
if err != nil {
return nil, err
}

return &q.Policy, nil
}

func (c *ExtendedGqlClient) AssignPolicy(ctx context.Context, spaceMrn string, action mondoov1.PolicyAction, policyMrns []string) error {
var list *[]mondoov1.String

Expand Down Expand Up @@ -448,6 +493,85 @@ func (c *ExtendedGqlClient) DeleteIntegration(ctx context.Context, mrn string) (
return &deleteMutation.DeleteClientIntegration, nil
}

type AzureConfigurationOptions struct {
TenantId string
ClientId string
SubscriptionsWhitelist []string
SubscriptionsBlacklist []string
ScanVms bool
}

type HostConfigurationOptions struct {
Host string `graphql:"host"`
HTTPS bool `graphql:"https"`
HTTP bool `graphql:"http"`
}

type SlackConfigurationOptions struct {
Placeholder string
}

type GithubConfigurationOptions struct {
Owner string
Repository string
Organization string
Type string
ReposAllowList []string
ReposDenyList []string
}

type Ms365ConfigurationOptions struct {
TenantId string
ClientId string
}

type HostedAwsConfigurationOptions struct {
AccessKeyId string
Role string
}

type GcpConfigurationOptions struct {
ProjectId string
DiscoverAll bool
}

type ClientIntegrationConfigurationOptions struct {
AzureConfigurationOptions AzureConfigurationOptions `graphql:"... on AzureConfigurationOptions"`
HostConfigurationOptions HostConfigurationOptions `graphql:"... on HostConfigurationOptions"`
Ms365ConfigurationOptions Ms365ConfigurationOptions `graphql:"... on Ms365ConfigurationOptions"`
GcpConfigurationOptions GcpConfigurationOptions `graphql:"... on GcpConfigurationOptions"`
SlackConfigurationOptions SlackConfigurationOptions `graphql:"... on SlackConfigurationOptions"`
GithubConfigurationOptions GithubConfigurationOptions `graphql:"... on GithubConfigurationOptions"`
HostedAwsConfigurationOptions HostedAwsConfigurationOptions `graphql:"... on HostedAwsConfigurationOptions"`
// Add other configuration options here
}

type Integration struct {
Mrn string
Name string
ConfigurationOptions ClientIntegrationConfigurationOptions `graphql:"configurationOptions"`
}

type ClientIntegration struct {
Integration Integration
}

func (c *ExtendedGqlClient) GetClientIntegration(ctx context.Context, mrn string) (Integration, error) {
var q struct {
ClientIntegration ClientIntegration `graphql:"clientIntegration(input: {mrn: $mrn})"`
}
variables := map[string]interface{}{
"mrn": mondoov1.String(mrn),
}

err := c.Query(ctx, &q, variables)
if err != nil {
return Integration{}, err
}

return q.ClientIntegration.Integration, nil
}

type triggerActionPayload struct {
Mrn string
}
Expand Down
26 changes: 25 additions & 1 deletion internal/provider/integration_aws_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"regexp"
"strings"

"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
Expand Down Expand Up @@ -279,5 +280,28 @@ func (r *integrationAwsResource) Delete(ctx context.Context, req resource.Delete
}

func (r *integrationAwsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("mrn"), req, resp)
mrn := req.ID
integration, err := r.client.GetClientIntegration(ctx, mrn)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to import AWS integration, got error: %s", err))
return
}

model := integrationAwsResourceModel{
SpaceId: types.StringValue(strings.Split(integration.Mrn, "/")[len(strings.Split(integration.Mrn, "/"))-3]),
Mrn: types.StringValue(integration.Mrn),
Name: types.StringValue(integration.Name),
Credential: integrationAwsCredentialModel{
Role: &roleCredentialModel{
RoleArn: types.StringValue(integration.ConfigurationOptions.HostedAwsConfigurationOptions.Role),
ExternalId: types.StringPointerValue(nil), // cannot be imported
},
Key: &accessKeyCredentialModel{
AccessKey: types.StringValue(integration.ConfigurationOptions.HostedAwsConfigurationOptions.AccessKeyId),
SecretKey: types.StringPointerValue(nil), // cannot be imported
},
},
}

resp.State.Set(ctx, &model)
}
Loading

0 comments on commit 358c827

Please sign in to comment.