Skip to content

Commit

Permalink
feat(onboarding,cloud-host-scanner): v2 enables cloud_account GCP WIF…
Browse files Browse the repository at this point in the history
… usage [SSPROD-35921] (#487)
  • Loading branch information
iru authored Mar 8, 2024
1 parent 2006771 commit 0aae6b7
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 58 deletions.
11 changes: 9 additions & 2 deletions .envrc.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# prod/kubelab
# export SYSDIG_SECURE_URL=https://secure.sysdig.com

# credentials
export SYSDIG_SECURE_API_TOKEN=
export SYSDIG_MONITOR_API_TOKEN=

# export SYSDIG_SECURE_URL=https://secure.sysdig.com

# whether to run local acc test
export TF_ACC=false

# terraform log level
export TF_LOG=DEBUG
78 changes: 30 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
<a href="https://terraform.io">
<img src="https://raw.githubusercontent.com/hashicorp/terraform-provider-aws/main/.github/terraform_logo.svg" alt="Terraform logo" title="Terraform" align="right" height="50" />
<img src="https://raw.githubusercontent.com/hashicorp/terraform-provider-aws/main/.github/terraform_logo.svg" alt="Terraform logo" title="Terraform" height="50" />
</a>


# Terraform Provider for Sysdig


- **[Terraform Registry - Sysdig Provider Docs](https://registry.terraform.io/providers/sysdiglabs/sysdig/latest/docs)**
- [Blog on how to use this provider with Sysdig Secure](https://sysdig.com/blog/using-terraform-for-container-security-as-code/)
- Terraform
- Website https://www.terraform.io
- Mailing list on [Google Groups](http://groups.google.com/group/terraform-tool)
- [![Gitter chat](https://badges.gitter.im/hashicorp-terraform/Lobby.png)](https://gitter.im/hashicorp-terraform/Lobby)


# Contribute
## Contribute

- [Initial Setup](#initial-setup)
- [Requirements](#requirements)
- [Develop](#develop)
- [Compile](#compile)
- [Test](#tests)
- [Install](#install-local)
- [Proposing PR's](#proposing-prs)
- [Release](#release)

## Initial Setup

### Building

#### Requirements
## Requirements

- [Terraform](https://www.terraform.io/downloads.html) > 0.12.x
- [Go](https://golang.org/doc/install) > Go version specified in [go.mod](./go.mod#L3)
- Correctly setup a [GOPATH](http://golang.org/doc/code.html#GOPATH), as well as adding `$GOPATH/bin` to your `$PATH`.

### Develop
## Develop

First **clone** source repository to: `$GOPATH/src/github.com/draios/terraform-provider-sysdig`

Expand All @@ -40,37 +35,36 @@ $ cd terraform-provider-sysdig
$ make build
```

### Compile
If you're a rookie, check [Official Terraform Provider development guides](https://developer.hashicorp.com/terraform/plugin/frameworkO)

### Creating new resource / data sources

TL;DR;
- Create the resource/data source item
- Add the created item into the `provider.go` resource or datasource map with its wiring
- With its [acceptance **test**](#tests)
- Add its **documentation** page on `./website/docs/`

## Compile

To **compile** the provider, run `make build`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.

```sh
$ make build
...
$ $GOPATH/bin/terraform-provider-sysdig
...
```

### Tests
In order to **test** the provider, you can simply run `make test`.
## Tests

```sh
$ make test
```
In order to **test** the provider, you can simply run `make test` to run unit-tests.
For acceptance tests, you can run `make testacc`, but note that
- Sysdig Montir and/or Secure credentials are required, check [`/.envrc.template`](https://github.com/sysdiglabs/terraform-provider-sysdig/blob/master/.envrc.template)
- **acceptance tests rely on the creation of real infrastructure**, you should execute them in an environment where you can remove the resources easily.

### Acceptance Tests
If you're a rookie, check [Terraform acceptance test guidelines](https://developer.hashicorp.com/terraform/plugin/testing)

If you want to execute the **acceptance tests**, you can run `make testacc`.
- Follow [Terraform acceptance test guideliness](https://www.terraform.io/plugin/sdkv2/testing/acceptance-tests)
- Please note that you need a token for Sysdig Monitor and another one for Sysdig Secure, and since the **acceptance tests create real infrastructure**
you should execute them in an environment where you can remove the resources easily.
- Acceptance tests are launched in [Sysdig production `+kubelab` test environment](https://github.com/sysdiglabs/terraform-provider-sysdig/blob/master/.github/workflows/ci-pull-request.yml#L82-L83)

```sh
$ make testacc
```

### Install (local)
## Install (local)
To use the local provider you just built, follow the instructions to [**install** it as a plugin.](https://www.terraform.io/docs/plugins/basics.html#installing-a-plugin) in your machine with:

```sh
Expand Down Expand Up @@ -100,20 +94,6 @@ To uninstall the plugin:
$ make uninstall
```

### Creating new resource / data sources

TL;DR;
- Create the resource/data source item
- Add the created item into the `provider.go` resource or datasource map with its wiring
- With its [acceptance **test**](#acceptance-tests)
- Add its **documentation** page on `./website/docs/`


Interesting resources
- https://www.terraform.io/plugin
- https://www.hashicorp.com/blog/testing-hashicorp-terraform


## Proposing PR's

* if it's your first time, validate you're taking into account every aspect of the [`./github/pull_request_template`](.github/pull_request_template.md)
Expand All @@ -122,7 +102,7 @@ Interesting resources
- You can work on this before even pushing to remote, using [**pre-commit**](https://pre-commit.com) plugin

* for the PR title use [conventional commit format](https://www.conventionalcommits.org/en/v1.0.0/) so when the branch is squashed to main branch it follows a convention
* for Acceptance Tests `testacc` some credentials are required, check [`/.envrc.template`](https://github.com/sysdiglabs/terraform-provider-sysdig/blob/master/.envrc.template)
* acceptance tests are launched in [Sysdig production `+kubelab` test environment](https://github.com/sysdiglabs/terraform-provider-sysdig/blob/master/.github/workflows/ci-pull-request.yml#L82-L83)


## Release
Expand All @@ -135,6 +115,8 @@ github/workflows/release.yml`](https://github.com/sysdiglabs/terraform-provider-
* Review Released Draft Note, and make it as clear as possible.
* Notify Sysdig teams on our internal #release-announcements slack channel and optionally in #terraform-provider

<br/><br/>

Mange takk!

![giphy](https://user-images.githubusercontent.com/1073243/200767344-7435f322-24c0-44d2-ac56-468791c84ca5.gif)
Expand Down
18 changes: 10 additions & 8 deletions sysdig/resource_sysdig_secure_cloud_auth_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ import (
"strings"
"time"

v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2"
cloudauth "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2/cloudauth/go"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/reflect/protoreflect"

v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2"
cloudauth "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2/cloudauth/go"
)

func resourceSysdigSecureCloudauthAccount() *schema.Resource {
timeout := 5 * time.Minute

var accountFeature = &schema.Resource{
accountFeature := &schema.Resource{
Schema: map[string]*schema.Schema{
SchemaType: {
Type: schema.TypeString,
Expand All @@ -43,7 +44,7 @@ func resourceSysdigSecureCloudauthAccount() *schema.Resource {
},
}

var accountFeatures = &schema.Resource{
accountFeatures := &schema.Resource{
Schema: map[string]*schema.Schema{
SchemaSecureConfigPosture: {
Type: schema.TypeSet,
Expand Down Expand Up @@ -73,7 +74,7 @@ func resourceSysdigSecureCloudauthAccount() *schema.Resource {
},
}

var accountComponents = &schema.Resource{
accountComponents := &schema.Resource{
Schema: map[string]*schema.Schema{
SchemaType: {
Type: schema.TypeString,
Expand Down Expand Up @@ -259,7 +260,6 @@ func resourceSysdigSecureCloudauthAccountDelete(ctx context.Context, data *schem
}

errStatus, err := client.DeleteCloudauthAccountSecure(ctx, data.Id())

if err != nil {
if strings.Contains(errStatus, "404") {
return nil
Expand Down Expand Up @@ -515,7 +515,7 @@ func componentsToResourceData(components []*cloudauth.AccountComponent) []map[st
case cloudauth.Component_COMPONENT_SERVICE_PRINCIPAL:
// XXX: handle GCP specially because keys are base64 encoded
if component.GetServicePrincipalMetadata().GetGcp() != nil {
gcpKeyBytes := []byte{}
var gcpKeyBytes []byte
if component.GetServicePrincipalMetadata().GetGcp().GetKey() != nil {
var err error
gcpKeyBytes, err = protojson.MarshalOptions{UseProtoNames: true}.Marshal(component.GetServicePrincipalMetadata().GetGcp().GetKey())
Expand Down Expand Up @@ -558,10 +558,12 @@ func componentsToResourceData(components []*cloudauth.AccountComponent) []map[st

// internal type redefintion for GCP service principals.
// This exists because in terraform, the key is originally provided in the form of a base64 encoded json string

// note; caution with order of fields, they have to go in alphabetical ASC so that the json marshalled on the tf read phase produces no drift https://github.com/golang/go/issues/27179
type internalServicePrincipalMetadata_GCP struct {
Email string `json:"email,omitempty"`
Key string `json:"key,omitempty"` // base64 encoded
WorkloadIdentityFederation *cloudauth.ServicePrincipalMetadata_GCP_WorkloadIdentityFederation `json:"workload_identity_federation,omitempty"`
Email string `json:"email,omitempty"`
}
type internalServicePrincipalMetadata struct {
Gcp *internalServicePrincipalMetadata_GCP `json:"gcp,omitempty"`
Expand Down
137 changes: 137 additions & 0 deletions sysdig/resource_sysdig_secure_cloud_auth_account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,140 @@ func TestAccAWSSecureCloudAccountFCCSPM(t *testing.T) {
},
})
}

func TestGCPAgentlesScanningOnboarding(t *testing.T) {
rText := func() string { return acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) }
accID := rText()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
if v := os.Getenv("SYSDIG_SECURE_API_TOKEN"); v == "" {
t.Fatal("SYSDIG_SECURE_API_TOKEN must be set for acceptance tests")
}
},
ProviderFactories: map[string]func() (*schema.Provider, error){
"sysdig": func() (*schema.Provider, error) {
return sysdig.Provider(), nil
},
},
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "sysdig_secure_cloud_auth_account" "gcp-agentless-scanning" {
provider_id = "gcp-agentless-test-%s"
provider_type = "PROVIDER_GCP"
enabled = true
feature {
secure_agentless_scanning {
enabled = true
components = ["COMPONENT_SERVICE_PRINCIPAL/secure-scanning"]
}
}
component {
type = "COMPONENT_SERVICE_PRINCIPAL"
instance = "secure-scanning"
service_principal_metadata = jsonencode({
gcp = {
workload_identity_federation = {
pool_provider_id = "pool_provider_id_value"
}
email = "email_value"
}
})
}
}`, accID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "provider_type", "PROVIDER_GCP"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "enabled", "true"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "feature.0.secure_agentless_scanning.0.enabled", "true"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "feature.0.secure_agentless_scanning.0.components.0", "COMPONENT_SERVICE_PRINCIPAL/secure-scanning"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.0.type", "COMPONENT_SERVICE_PRINCIPAL"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.0.instance", "secure-scanning"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.0.service_principal_metadata", "{\"gcp\":{\"email\":\"email_value\",\"workload_identity_federation\":{\"pool_provider_id\":\"pool_provider_id_value\"}}}"),
),
},
{
ResourceName: "sysdig_secure_cloud_auth_account.gcp-agentless-scanning",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestGCPAgentlesScanningOnboardingWithInventory(t *testing.T) {
rText := func() string { return acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) }
accountID := rText()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
if v := os.Getenv("SYSDIG_SECURE_API_TOKEN"); v == "" {
t.Fatal("SYSDIG_SECURE_API_TOKEN must be set for acceptance tests")
}
},
ProviderFactories: map[string]func() (*schema.Provider, error){
"sysdig": func() (*schema.Provider, error) {
return sysdig.Provider(), nil
},
},
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "sysdig_secure_cloud_auth_account" "gcp-agentless-scanning" {
provider_id = "gcp-agentless-test-%s"
provider_type = "PROVIDER_GCP"
enabled = true
feature {
secure_config_posture {
enabled = true
components = ["COMPONENT_SERVICE_PRINCIPAL/secure-posture"]
}
secure_agentless_scanning {
enabled = true
components = ["COMPONENT_SERVICE_PRINCIPAL/secure-scanning"]
}
}
component {
type = "COMPONENT_SERVICE_PRINCIPAL"
instance = "secure-posture"
service_principal_metadata = jsonencode({
gcp = {
key = "%s"
}
})
}
component {
type = "COMPONENT_SERVICE_PRINCIPAL"
instance = "secure-scanning"
service_principal_metadata = jsonencode({
gcp = {
workload_identity_federation = {
pool_provider_id = "pool_provider_id_value"
}
email = "email_value"
}
})
}
}`, accountID, getEncodedServiceAccountKey("sample-1", accountID)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "provider_type", "PROVIDER_GCP"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "enabled", "true"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "feature.0.secure_agentless_scanning.0.enabled", "true"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "feature.0.secure_agentless_scanning.0.components.0", "COMPONENT_SERVICE_PRINCIPAL/secure-scanning"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.0.type", "COMPONENT_SERVICE_PRINCIPAL"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.0.instance", "secure-posture"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.0.service_principal_metadata", "{\"gcp\":{\"key\":\""+getEncodedServiceAccountKey("sample-1", accountID)+"\"}}"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.1.instance", "secure-scanning"),
resource.TestCheckResourceAttr("sysdig_secure_cloud_auth_account.gcp-agentless-scanning", "component.1.service_principal_metadata", "{\"gcp\":{\"email\":\"email_value\",\"workload_identity_federation\":{\"pool_provider_id\":\"pool_provider_id_value\"}}}"),
),
},
{
ResourceName: "sysdig_secure_cloud_auth_account.gcp-agentless-scanning",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

0 comments on commit 0aae6b7

Please sign in to comment.