Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE]: feat(RAIN-66370): add support in the CLI for existing topic and sub for GCP Pub/Sub Audit Log #1339

Closed
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ locally you need to setup the following environment variables and use the direct
`make integration`, an example of the command you can use is:
```
CI_ACCOUNT="<YOUR_ACCOUNT>" \
CI_V1_ACCOUNT="<YOUR_V1_CONFIG_ACCOUNT>" \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

CI_SUBACCOUNT="<YOUR_SUBACCOUNT_IF_ANY>" \
CI_API_KEY="<YOUR_API_KEY>" \
CI_API_SECRET="<YOUR_API_SECRET>" \
Expand All @@ -210,8 +209,6 @@ This is a list of all environment variables used in the running the integration
| Environment Variable | Description |
|----------------------|-------------|
|`CI_ACCOUNT="<YOUR_ACCOUNT>"` | account subdomain of URL (i.e. `<ACCOUNT>.lacework.net`)|
|`CI_V1_ACCOUNT="<YOUR_V1_CONFIG_ACCOUNT>"` | for standalone accounts use the same as `CI_ACCOUNT`, for organizations
use `CI_SUBACCOUNT`|
|`CI_SUBACCOUNT="<YOUR_ACCOUNT>"` | (orgs only) a sub-account|
|`CI_API_KEY="<YOUR_ACCOUNT>"` | API access key id|
|`CI_API_SECRET="<YOUR_ACCOUNT>"` | API secret access key|
Expand Down
81 changes: 64 additions & 17 deletions cli/cmd/generate_gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,20 @@ var (
QuestionExistingServiceAccountName = "Specify an existing service account name:"
QuestionExistingServiceAccountPrivateKey = "Specify an existing service account private key (base64 encoded):"

GcpAdvancedOptAuditLog = "Configure additional Audit Log options"
QuestionGcpUseExistingBucket = "Use an existing bucket?"
QuestionGcpExistingBucketName = "Specify an existing bucket name:"
QuestionGcpConfigureNewBucket = "Configure settings for new bucket?"
QuestionGcpBucketRegion = "Specify the bucket region: (optional)"
QuestionGcpCustomBucketName = "Specify a custom bucket name: (optional)"
QuestionGcpBucketLifecycle = "Specify the bucket lifecycle rule age: (optional)"
QuestionGcpEnableUBLA = "Enable uniform bucket level access(UBLA)?"
QuestionGcpUseExistingSink = "Use an existing sink?"
QuestionGcpExistingSinkName = "Specify the existing sink name"
GcpAdvancedOptAuditLog = "Configure additional Audit Log options"
QuestionGcpUseExistingBucket = "Use an existing bucket?"
QuestionGcpExistingBucketName = "Specify an existing bucket name:"
QuestionGcpConfigureNewBucket = "Configure settings for new bucket?"
QuestionGcpBucketRegion = "Specify the bucket region: (optional)"
QuestionGcpCustomBucketName = "Specify a custom bucket name: (optional)"
QuestionGcpBucketLifecycle = "Specify the bucket lifecycle rule age: (optional)"
QuestionGcpEnableUBLA = "Enable uniform bucket level access(UBLA)?"
QuestionGcpUseExistingSink = "Use an existing sink?"
QuestionGcpExistingSinkName = "Specify the existing sink name:"
QuestionGcpUseExistingPubSubTopic = "Use an existing Pub/Sub topic?"
QuestionGcpExistingPubSubTopicId = "Specify the existing Pub/Sub topic ID:"
QuestionGcpUseExistingPubSubSubscription = "Use an existing Pub/Sub subscription?"
QuestionGcpExistingPubSubSubscriptionName = "Specify the existing Pub/Sub subscription name:"

GcpAdvancedOptIntegrationName = "Customize integration name(s)"
QuestionGcpConfigurationIntegrationName = "Specify a custom configuration integration name: (optional)"
Expand Down Expand Up @@ -112,6 +116,8 @@ See help output for more details on the parameter value(s) required for Terrafor
gcp.WithBucketRegion(GenerateGcpCommandState.BucketRegion),
gcp.WithExistingLogBucketName(GenerateGcpCommandState.ExistingLogBucketName),
gcp.WithExistingLogSinkName(GenerateGcpCommandState.ExistingLogSinkName),
gcp.WithExistingPubSubTopicId(GenerateGcpCommandState.ExistingPubSubTopicId),
gcp.WithExistingPubSubSubscriptionName(GenerateGcpCommandState.ExistingPubSubSubscriptionName),
gcp.WithAuditLogIntegrationName(GenerateGcpCommandState.AuditLogIntegrationName),
gcp.WithLaceworkProfile(GenerateGcpCommandState.LaceworkProfile),
gcp.WithLogBucketLifecycleRuleAge(GenerateGcpCommandState.LogBucketLifecycleRuleAge),
Expand Down Expand Up @@ -274,13 +280,15 @@ See help output for more details on the parameter value(s) required for Terrafor
)

type GcpGenerateCommandExtraState struct {
AskAdvanced bool
Output string
ConfigureNewBucketSettings bool
UseExistingServiceAccount bool
UseExistingBucket bool
UseExistingSink bool
TerraformApply bool
AskAdvanced bool
Output string
ConfigureNewBucketSettings bool
UseExistingServiceAccount bool
UseExistingBucket bool
UseExistingSink bool
UseExistingPubSubTopic bool
UseExistingPubSubSubscription bool
TerraformApply bool
}

func (gcp *GcpGenerateCommandExtraState) isEmpty() bool {
Expand All @@ -289,6 +297,8 @@ func (gcp *GcpGenerateCommandExtraState) isEmpty() bool {
!gcp.UseExistingServiceAccount &&
!gcp.UseExistingBucket &&
!gcp.UseExistingSink &&
!gcp.UseExistingPubSubTopic &&
!gcp.UseExistingPubSubSubscription &&
!gcp.TerraformApply
}

Expand Down Expand Up @@ -368,6 +378,16 @@ func initGenerateGcpTfCommandFlags() {
"existing_sink_name",
"",
"specify existing sink name")
generateGcpTfCommand.PersistentFlags().StringVar(
&GenerateGcpCommandState.ExistingPubSubTopicId,
"existing_pub_sub_topic_id",
"",
"specify existing pub/sub topic id")
generateGcpTfCommand.PersistentFlags().StringVar(
&GenerateGcpCommandState.ExistingPubSubSubscriptionName,
"existing_pub_sub_subscription_name",
"",
"specify existing pub/sub subscription name")

// DEPRECATED
generateGcpTfCommand.PersistentFlags().BoolVar(
Expand Down Expand Up @@ -517,6 +537,33 @@ func promptGcpAuditLogQuestions(
Required: true,
Response: &config.ExistingLogSinkName,
},
{
Prompt: &survey.Confirm{Message: QuestionGcpUseExistingPubSubTopic,
Default: extraState.UseExistingPubSubTopic},
Checks: []*bool{&config.AuditLog, &config.UsePubSubAudit},
Required: true,
Response: &extraState.UseExistingPubSubTopic,
},
{
Prompt: &survey.Input{Message: QuestionGcpExistingPubSubTopicId, Default: config.ExistingPubSubTopicId},
Checks: []*bool{&config.AuditLog, &config.UsePubSubAudit, &extraState.UseExistingPubSubTopic},
Required: true,
Response: &config.ExistingPubSubTopicId,
},
{
Prompt: &survey.Confirm{Message: QuestionGcpUseExistingPubSubSubscription,
Default: extraState.UseExistingPubSubSubscription},
Checks: []*bool{&config.AuditLog, &config.UsePubSubAudit},
Required: true,
Response: &extraState.UseExistingPubSubSubscription,
},
{
Prompt: &survey.Input{Message: QuestionGcpExistingPubSubSubscriptionName,
Default: config.ExistingPubSubSubscriptionName},
Checks: []*bool{&config.AuditLog, &config.UsePubSubAudit, &extraState.UseExistingPubSubSubscription},
Required: true,
Response: &config.ExistingPubSubSubscriptionName,
},
{
Prompt: &survey.Input{Message: QuestionGcpCustomFilter, Default: config.CustomFilter},
Checks: []*bool{&config.AuditLog},
Expand Down
2 changes: 2 additions & 0 deletions cli/docs/lacework_generate_cloud-account_gcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ lacework generate cloud-account gcp [flags]
--custom_filter string Audit Log filter which supersedes all other filter options when defined
--enable_ubla enable universal bucket level access(ubla) (default true)
--existing_bucket_name string specify existing bucket name
--existing_pub_sub_subscription_name string specify existing pub/sub subscription name
--existing_pub_sub_topic_id string specify existing pub/sub topic id
--existing_service_account_name string specify existing service account name
--existing_service_account_private_key string specify existing service account private key (base64 encoded)
--existing_sink_name string specify existing sink name
Expand Down
52 changes: 52 additions & 0 deletions integration/gcp_generation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ func TestGenerationPubSubAuditlogOnlyGcp(t *testing.T) {
MsgMenu{cmd.GcpAdvancedOptAuditLog, 0},
MsgRsp{cmd.QuestionUsePubSubAudit, "y"},
MsgRsp{cmd.QuestionGcpUseExistingSink, "n"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubTopic, "n"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubSubscription, "n"},
MsgRsp{cmd.QuestionGcpCustomFilter, ""},
MsgRsp{cmd.QuestionGcpAnotherAdvancedOpt, "n"},
MsgRsp{cmd.QuestionRunTfPlan, "n"},
Expand All @@ -181,6 +183,52 @@ func TestGenerationPubSubAuditlogOnlyGcp(t *testing.T) {
assert.Equal(t, buildTf, tfResult)
}

// Test pub-sub audit log with existing topic and subscription
func TestGenerationPubSubAuditLogExistingTopicAndSubscriptionGcp(t *testing.T) {
os.Setenv("LW_NOCACHE", "true")
defer os.Setenv("LW_NOCACHE", "")
var final string

tfResult := runGcpGenerateTest(t,
func(c *expect.Console) {
expectsCliOutput(t, c, []MsgRspHandler{
MsgRsp{cmd.QuestionGcpEnableConfiguration, "n"},
MsgRsp{cmd.QuestionGcpEnableAuditLog, "y"},
MsgRsp{cmd.QuestionGcpProjectID, projectId},
MsgRsp{cmd.QuestionGcpOrganizationIntegration, "n"},
MsgRsp{cmd.QuestionGcpServiceAccountCredsPath, ""},
MsgRsp{cmd.QuestionGcpConfigureAdvanced, "y"},
MsgMenu{cmd.GcpAdvancedOptAuditLog, 0},
MsgRsp{cmd.QuestionUsePubSubAudit, "y"},
MsgRsp{cmd.QuestionGcpUseExistingSink, "y"},
MsgRsp{cmd.QuestionGcpExistingSinkName, "sink"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubTopic, "y"},
MsgRsp{cmd.QuestionGcpExistingPubSubTopicId, "topic"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubSubscription, "y"},
MsgRsp{cmd.QuestionGcpExistingPubSubSubscriptionName, "subscription"},
MsgRsp{cmd.QuestionGcpCustomFilter, ""},
MsgRsp{cmd.QuestionGcpAnotherAdvancedOpt, "n"},
MsgRsp{cmd.QuestionRunTfPlan, "n"},
})

final, _ = c.ExpectEOF()
},
"generate",
"cloud-account",
"gcp",
)

assertTerraformSaved(t, final)

buildTf, _ := gcp.NewTerraform(false, true, true,
gcp.WithProjectId(projectId),
gcp.WithExistingLogSinkName("sink"),
gcp.WithExistingPubSubTopicId("topic"),
gcp.WithExistingPubSubSubscriptionName("subscription"),
).Generate()
assert.Equal(t, buildTf, tfResult)
}

func TestGenerationPubSubAuditlogOrgGcp(t *testing.T) {
os.Setenv("LW_NOCACHE", "true")
defer os.Setenv("LW_NOCACHE", "")
Expand All @@ -199,6 +247,8 @@ func TestGenerationPubSubAuditlogOrgGcp(t *testing.T) {
MsgMenu{cmd.GcpAdvancedOptAuditLog, 0},
MsgRsp{cmd.QuestionUsePubSubAudit, "y"},
MsgRsp{cmd.QuestionGcpUseExistingSink, "n"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubTopic, "n"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubSubscription, "n"},
MsgRsp{cmd.QuestionGcpCustomFilter, ""},
MsgRsp{cmd.QuestionGcpAnotherAdvancedOpt, "n"},
MsgRsp{cmd.QuestionRunTfPlan, "n"},
Expand Down Expand Up @@ -692,6 +742,8 @@ func TestGenerationPubSubUseExistingSA(t *testing.T) {
MsgMenu{cmd.GcpAdvancedOptAuditLog, 0},
MsgRsp{cmd.QuestionUsePubSubAudit, "y"},
MsgRsp{cmd.QuestionGcpUseExistingSink, "n"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubTopic, "n"},
MsgRsp{cmd.QuestionGcpUseExistingPubSubSubscription, "n"},
MsgRsp{cmd.QuestionGcpCustomFilter, ""},
MsgRsp{cmd.QuestionGcpAnotherAdvancedOpt, "y"},
MsgMenu{cmd.GcpAdvancedOptAuditLog, 1},
Expand Down
2 changes: 2 additions & 0 deletions integration/test_resources/help/generate_cloud-account_gcp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Flags:
--custom_filter string Audit Log filter which supersedes all other filter options when defined
--enable_ubla enable universal bucket level access(ubla) (default true)
--existing_bucket_name string specify existing bucket name
--existing_pub_sub_subscription_name string specify existing pub/sub subscription name
--existing_pub_sub_topic_id string specify existing pub/sub topic id
--existing_service_account_name string specify existing service account name
--existing_service_account_private_key string specify existing service account private key (base64 encoded)
--existing_sink_name string specify existing sink name
Expand Down
19 changes: 19 additions & 0 deletions lwgenerate/_examples/gcp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ func existingGcpBucketAndSink() {
fmt.Printf("\n-----\n%s", hcl)
}

func existingTopicAndSubscription() {
hcl, err := gcp.NewTerraform(
true,
true,
gcp.WithProjectId("example_project"),
gcp.WithGcpServiceAccountCredentials("path/to/service/account/creds.json"),
gcp.WithExistingPubSubTopicId("existing_pub_sub_topic_id"),
gcp.WithExistingPubSubSubscriptionName("existing_pub_sub_subscription_name"),
).Generate()

if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}

fmt.Printf("\n-----\n%s", hcl)
}

func gcpWithLaceworkProfile() {
hcl, err := gcp.NewTerraform(
true,
Expand Down Expand Up @@ -126,6 +144,7 @@ func main() {
basic()
existingGcpServiceAccount()
existingGcpBucketAndSink()
existingTopicAndSubscription()
gcpWithLaceworkProfile()
configOnly()
auditLogOnly()
Expand Down
30 changes: 29 additions & 1 deletion lwgenerate/gcp/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ type GenerateGcpTfConfigurationArgs struct {
// Existing Sink Name
ExistingLogSinkName string

// Existing Topic Name
ExistingPubSubTopicId string

// Existing Subscription Name
ExistingPubSubSubscriptionName string

// Should we force destroy the bucket if it has stuff in it? (only relevant on new Audit Log creation)
// DEPRECATED
EnableForceDestroyBucket bool
Expand Down Expand Up @@ -307,6 +313,20 @@ func WithExistingLogSinkName(name string) GcpTerraformModifier {
}
}

// WithExistingPubSubTopicId Set the Topic ID of an existing Audit Log Topic Setup
func WithExistingPubSubTopicId(name string) GcpTerraformModifier {
return func(c *GenerateGcpTfConfigurationArgs) {
c.ExistingPubSubTopicId = name
}
}

// WithExistingPubSubSubscriptionName Set the Topic Subscription Name of an existing Audit Log Subscription Setup
func WithExistingPubSubSubscriptionName(name string) GcpTerraformModifier {
return func(c *GenerateGcpTfConfigurationArgs) {
c.ExistingPubSubSubscriptionName = name
}
}

// WithEnableUBLA Enable force destroy of the bucket if it has stuff in it
func WithEnableUBLA(enable bool) GcpTerraformModifier {
return func(c *GenerateGcpTfConfigurationArgs) {
Expand Down Expand Up @@ -597,6 +617,14 @@ func createAuditLog(args *GenerateGcpTfConfigurationArgs) (*hclwrite.Block, erro
attributes["existing_sink_name"] = args.ExistingLogSinkName
}

if args.ExistingPubSubTopicId != "" {
attributes["existing_pub_sub_topic_id"] = args.ExistingPubSubTopicId
}

if args.ExistingPubSubSubscriptionName != "" {
attributes["existing_pub_sub_subscription_name"] = args.ExistingPubSubSubscriptionName
}

// default to using the project level module
auditLogModuleName := "gcp_project_audit_log"

Expand All @@ -605,7 +633,7 @@ func createAuditLog(args *GenerateGcpTfConfigurationArgs) (*hclwrite.Block, erro
// if organization integration is true, override configModuleName to use the organization level module
configurationModuleName = "gcp_organization_level_config"
auditLogModuleName = "gcp_organization_level_audit_log"
// Determine if this is the a pub-sub audit log
// Determine if this is a pub-sub audit log
if args.UsePubSubAudit {
attributes["integration_type"] = "ORGANIZATION"
} else {
Expand Down
52 changes: 52 additions & 0 deletions lwgenerate/gcp/gcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,35 @@ func TestGenerateGcpTfConfigurationArgs_Generate_AuditLog(t *testing.T) {
),
ReqProvider(projectName, moduleImportProjectLevelPubSubAuditLogExistingLogSinkName),
},
{
"TestGenerationProjectLevelPubSubAuditLogExistingPubSubTopicId",
gcp.NewTerraform(false, true, true,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
gcp.WithProjectId(projectName),
gcp.WithExistingPubSubTopicId("topicMcTopicFace"),
),
ReqProvider(projectName, moduleImportProjectLevelPubSubAuditLogExistingPubSubTopicId),
},
{
"TestGenerationProjectLevelPubSubAuditLogExistingPubSubSubscriptionName",
gcp.NewTerraform(false, true, true,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
gcp.WithProjectId(projectName),
gcp.WithExistingPubSubSubscriptionName("subscriptionMcSubscriptionFace"),
),
ReqProvider(projectName, moduleImportProjectLevelPubSubAuditLogExistingPubSubSubscriptionName),
},
{
"TestGenerationProjectLevelPubSubAuditLogExistingSinkAndExistingPubSubResources",
gcp.NewTerraform(false, true, true,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
gcp.WithProjectId(projectName),
gcp.WithExistingPubSubSubscriptionName("subscriptionMcSubscriptionFace"),
gcp.WithExistingPubSubTopicId("topicMcTopicFace"),
gcp.WithExistingLogSinkName("fooSink"),
),
ReqProvider(projectName, moduleImportProjectLevelPubSubAuditLogExistingSinkAndExistingPubSubResources),
},
{"TestGenerationProjectLevelAuditLogEnableUBLA",
gcp.NewTerraform(false, true, false,
gcp.WithGcpServiceAccountCredentials("/path/to/credentials"),
Expand Down Expand Up @@ -882,6 +911,29 @@ var moduleImportProjectLevelPubSubAuditLogExistingLogSinkName = `module "gcp_pro
}
`

var moduleImportProjectLevelPubSubAuditLogExistingPubSubTopicId = `module "gcp_project_audit_log" {
source = "lacework/pub-sub-audit-log/gcp"
version = "~> 0.2"
existing_pub_sub_topic_id = "topicMcTopicFace"
}
`

var moduleImportProjectLevelPubSubAuditLogExistingPubSubSubscriptionName = `module "gcp_project_audit_log" {
source = "lacework/pub-sub-audit-log/gcp"
version = "~> 0.2"
existing_pub_sub_subscription_name = "subscriptionMcSubscriptionFace"
}
`

var moduleImportProjectLevelPubSubAuditLogExistingSinkAndExistingPubSubResources = `module "gcp_project_audit_log" {
source = "lacework/pub-sub-audit-log/gcp"
version = "~> 0.2"
existing_pub_sub_subscription_name = "subscriptionMcSubscriptionFace"
existing_pub_sub_topic_id = "topicMcTopicFace"
existing_sink_name = "fooSink"
}
`

var moduleImportProjectLevelAuditLogEnableUBLA = `module "gcp_project_audit_log" {
source = "lacework/audit-log/gcp"
version = "~> 3.4"
Expand Down