Skip to content

Commit

Permalink
feat(api): add v2 AwsCfg (#889)
Browse files Browse the repository at this point in the history
* feat: add v2 AwsCfg

Signed-off-by: Darren Murray <[email protected]>
  • Loading branch information
dmurray-lacework authored Aug 18, 2022
1 parent a8f9ee4 commit 53bd1ca
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 5 deletions.
57 changes: 57 additions & 0 deletions api/_examples/cloud-accounts/aws-cfg/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"fmt"
"log"
"os"

"github.com/lacework/go-sdk/api"
)

func main() {
lacework, err := api.NewClient(os.Getenv("LW_ACCOUNT"),
api.WithSubaccount(os.Getenv("LW_SUBACCOUNT")),
api.WithApiKeys(os.Getenv("LW_API_KEY"), os.Getenv("LW_API_SECRET")),
api.WithApiV2(),
)
if err != nil {
log.Fatal(err)
}

res, err := lacework.V2.CloudAccounts.List()
if err != nil {
log.Fatal(err)
}

for _, account := range res.Data {
support := "Unsupported"
switch account.Type {
case api.AwsCfgCloudAccount.String():
support = "Supported"
}

// Output: INTEGRATION-GUID:INTEGRATION-TYPE:[Supported|Unsupported]
fmt.Printf("%s:%s:%s\n", account.IntgGuid, account.Type, support)
}

awsCfgData := api.AwsCfgData{
Credentials: api.AwsCfgCredentials{
RoleArn: "arn:aws:iam::1234567890:role/lacework_iam_example_role",
ExternalID: "abc123",
},
}

awsCtSqsCloudAccount := api.NewCloudAccount(
"aws-cfg-from-golang",
api.AwsCfgCloudAccount,
awsCfgData,
)

awsCfgResponse, err := lacework.V2.CloudAccounts.Create(awsCtSqsCloudAccount)
if err != nil {
log.Fatal(err)
}

// Output: AwsCfg Cloud Account created: THE-INTEGRATION-GUID
fmt.Printf("Cloud Account created: %s", awsCfgResponse.Data.IntgGuid)
}
57 changes: 57 additions & 0 deletions api/cloud_accounts_aws_cfg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Author:: Darren Murray (<[email protected]>)
// Copyright:: Copyright 2022, Lacework Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package api

// GetAwsCfg gets a single AwsCfg integration matching the
// provided integration guid
func (svc *CloudAccountsService) GetAwsCfg(guid string) (
response AwsCfgIntegrationResponse,
err error,
) {
err = svc.get(guid, &response)
return
}

// UpdateAwsCfg updates a single AwsCfg integration on the Lacework Server
func (svc *CloudAccountsService) UpdateAwsCfg(data CloudAccount) (
response AwsCfgIntegrationResponse,
err error,
) {
err = svc.update(data.ID(), data, &response)
return
}

type AwsCfgIntegrationResponse struct {
Data AwsCfg `json:"data"`
}

type AwsCfg struct {
v2CommonIntegrationData
Data AwsCfgData `json:"data"`
}

type AwsCfgData struct {
Credentials AwsCfgCredentials `json:"crossAccountCredentials"`
AwsAccountID string `json:"awsAccountId,omitempty"`
}

type AwsCfgCredentials struct {
RoleArn string `json:"roleArn"`
ExternalID string `json:"externalId"`
}
163 changes: 163 additions & 0 deletions api/cloud_accounts_aws_cfg_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//
// Author:: Darren Murray (<[email protected]>)
// Copyright:: Copyright 2022, Lacework Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package api_test

import (
"fmt"
"net/http"
"testing"

"github.com/stretchr/testify/assert"

"github.com/lacework/go-sdk/api"
"github.com/lacework/go-sdk/internal/intgguid"
"github.com/lacework/go-sdk/internal/lacework"
)

func TestCloudAccountsNewAwsCfgWithCustomTemplateFile(t *testing.T) {
awsCfgData := api.AwsCfgData{
Credentials: api.AwsCfgCredentials{
RoleArn: "arn:foo:bar",
ExternalID: "0123456789",
},
}

subject := api.NewCloudAccount("integration_name", api.AwsCfgCloudAccount, awsCfgData)
assert.Equal(t, api.AwsCfgCloudAccount.String(), subject.Type)

// casting the data interface{} to type AwsCfgData
subjectData := subject.Data.(api.AwsCfgData)

assert.Equal(t, subjectData.Credentials.RoleArn, "arn:foo:bar")
assert.Equal(t, subjectData.Credentials.ExternalID, "0123456789")
}

func TestCloudAccountsAwsCfgGet(t *testing.T) {
var (
intgGUID = intgguid.New()
apiPath = fmt.Sprintf("CloudAccounts/%s", intgGUID)
fakeServer = lacework.MockServer()
)
fakeServer.UseApiV2()
fakeServer.MockToken("TOKEN")
defer fakeServer.Close()

fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "GET", r.Method, "GetAwsCfg() should be a GET method")
fmt.Fprintf(w, generateCloudAccountResponse(singleAwsCfgCloudAccount(intgGUID)))
})

c, err := api.NewClient("test",
api.WithApiV2(),
api.WithToken("TOKEN"),
api.WithURL(fakeServer.URL()),
)
assert.Nil(t, err)

response, err := c.V2.CloudAccounts.GetAwsCfg(intgGUID)
assert.Nil(t, err)
assert.NotNil(t, response)
assert.Equal(t, intgGUID, response.Data.IntgGuid)
assert.Equal(t, "integration_name", response.Data.Name)
assert.True(t, response.Data.State.Ok)
assert.Equal(t, "arn:foo:bar", response.Data.Data.Credentials.RoleArn)
assert.Equal(t, "0123456789", response.Data.Data.Credentials.ExternalID)
}

func TestCloudAccountsAwsCfgUpdate(t *testing.T) {
var (
intgGUID = intgguid.New()
apiPath = fmt.Sprintf("CloudAccounts/%s", intgGUID)
fakeServer = lacework.MockServer()
)
fakeServer.UseApiV2()
fakeServer.MockToken("TOKEN")
defer fakeServer.Close()

fakeServer.MockAPI(apiPath, func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "PATCH", r.Method, "UpdateAwsCfg() should be a PATCH method")

if assert.NotNil(t, r.Body) {
body := httpBodySniffer(r)
assert.Contains(t, body, intgGUID, "INTG_GUID missing")
assert.Contains(t, body, "integration_name", "cloud account name is missing")
assert.Contains(t, body, "AwsCfg", "wrong cloud account type")
assert.Contains(t, body, "arn:foo:bar", "wrong role arn")
assert.Contains(t, body, "0123456789", "wrong external ID")
assert.Contains(t, body, "enabled\":1", "cloud account is not enabled")
}

fmt.Fprintf(w, generateCloudAccountResponse(singleAwsCfgCloudAccount(intgGUID)))
})

c, err := api.NewClient("test",
api.WithApiV2(),
api.WithToken("TOKEN"),
api.WithURL(fakeServer.URL()),
)
assert.Nil(t, err)

cloudAccount := api.NewCloudAccount("integration_name",
api.AwsCfgCloudAccount,
api.AwsCfgData{
Credentials: api.AwsCfgCredentials{
RoleArn: "arn:foo:bar",
ExternalID: "0123456789",
},
},
)
assert.Equal(t, "integration_name", cloudAccount.Name, "AwsCfg cloud account name mismatch")
assert.Equal(t, "AwsCfg", cloudAccount.Type, "a new AwsCfg cloud account should match its type")
assert.Equal(t, 1, cloudAccount.Enabled, "a new AwsCfg cloud account should be enabled")
cloudAccount.IntgGuid = intgGUID

response, err := c.V2.CloudAccounts.UpdateAwsCfg(cloudAccount)
assert.Nil(t, err)
assert.NotNil(t, response)
assert.Equal(t, intgGUID, response.Data.IntgGuid)
assert.Equal(t, "arn:foo:bar", response.Data.Data.Credentials.RoleArn)
assert.Equal(t, "0123456789", response.Data.Data.Credentials.ExternalID)
}

func singleAwsCfgCloudAccount(id string) string {
return `
{
"createdOrUpdatedBy": "[email protected]",
"createdOrUpdatedTime": "2021-06-01T19:28:00.092Z",
"data": {
"awsAccountId": "123456789000",
"crossAccountCredentials": {
"externalId": "0123456789",
"roleArn": "arn:foo:bar"
}
},
"enabled": 1,
"intgGuid": "` + id + `",
"isOrg": 0,
"name": "integration_name",
"state": {
"details": {},
"lastSuccessfulTime": 1624456896915,
"lastUpdatedTime": 1624456896915,
"ok": true
},
"type": "AwsCfg"
}
`
}
10 changes: 5 additions & 5 deletions api/cloud_accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,13 @@ func TestCloudAccountsDelete(t *testing.T) {
func TestCloudAccountsList(t *testing.T) {
var (
awsIntgGUIDs = []string{intgguid.New(), intgguid.New(), intgguid.New()}
awsCfgGUIDs = []string{intgguid.New(), intgguid.New(), intgguid.New()}
awsEksAuditLogGUIDs = []string{intgguid.New()}
azureIntgGUIDs = []string{intgguid.New(), intgguid.New()}
gcpIntgGUIDs = []string{
intgguid.New(), intgguid.New(), intgguid.New(), intgguid.New(),
}
allGUIDs = append(awsEksAuditLogGUIDs, append(azureIntgGUIDs, append(gcpIntgGUIDs, awsIntgGUIDs...)...)...)
allGUIDs = append(awsEksAuditLogGUIDs, append(azureIntgGUIDs, append(awsCfgGUIDs, append(gcpIntgGUIDs, awsIntgGUIDs...)...)...)...)
expectedLen = len(allGUIDs)
fakeServer = lacework.MockServer()
)
Expand All @@ -201,6 +202,7 @@ func TestCloudAccountsList(t *testing.T) {
generateCloudAccounts(awsIntgGUIDs, "AwsCtSqs"),
generateCloudAccounts(awsEksAuditLogGUIDs, "AwsEksAudit"),
// TODO @afiune come back here and update these Cloud Accounts types when they exist
generateCloudAccounts(awsCfgGUIDs, "AwsCfg"),
generateCloudAccounts(gcpIntgGUIDs, "AwsCtSqs"), // "GcpCfg"),
generateCloudAccounts(azureIntgGUIDs, "AwsCtSqs"), // "AzureAlSeq"),
}
Expand Down Expand Up @@ -277,10 +279,8 @@ func generateCloudAccounts(guids []string, iType string) string {
cloudAccounts[i] = singleAwsCtSqsCloudAccount(guid)
case api.AwsEksAuditCloudAccount.String():
cloudAccounts[i] = singleAwsEksAuditCloudAccount(guid)
// TODO @afiune come back here and update these Cloud Accounts types
// when they exist
//case api.AwsCfgCloudAccount.String():
//cloudAccounts[i] = singleAwsCfgCloudAccount(guid)
case api.AwsCfgCloudAccount.String():
cloudAccounts[i] = singleAwsCfgCloudAccount(guid)
}
}
return strings.Join(cloudAccounts, ", ")
Expand Down

0 comments on commit 53bd1ca

Please sign in to comment.