diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md
new file mode 100644
index 0000000..014d9ed
--- /dev/null
+++ b/DEPLOYMENT.md
@@ -0,0 +1,171 @@
+# Example Deployments
+
+There are a couple of component involved in utilizing the crawler
+
+1. Deploy the module
+2. Network Considerations
+3. Secrets
+4. Data Repo Scan Schedule (Event Bridge Rule)
+
+## Deploy the module
+
+The module deployment itself is pretty simple and will deploy a lambda
+
+```terraform
+module "cyral_repo_crawler" {
+ source = "cyralinc/repo-crawler/aws"
+ version = "~> 1.0"
+ crawler_version = "v0.12.4"
+ control_plane_host = "example.app.cyral.com"
+
+ # These are optional depending on if you the DB is publically accessible or not
+ vpc_id = "vpc-1234"
+ subnet_ids = ["subnet-1234","subnet-5678"]
+
+ # Create a set of credentials on the control plane
+ cyral_client_id = "sa/default/12345"
+ cyral_client_secret = "asdf12345"
+
+ # This is used to provide the lambda access to any database secrets to run the crawler.
+ repo_secret_arns = [ "arn:aws:secretsmanager:us-east-1:111222333444:secret:/cyral/*" ]
+
+}
+```
+
+## Network Considerations
+
+In order for the crawler to access databases that are not internet accessible a VPC and Subnets will need to be provided via the `vpc_id` and `subnet_ids` variables. The Provided subnets will need outbound internet access to communicate with the controlplane.
+If the database is internet accessible you can skip the `vpc_id` and `subnet_ids` variables
+
+## Secrets
+
+The Repo Crawler will need access to the database with local credentials which should be stored in a Secret.
+To allow the Lambda to access those secrets you'll have to provide the ARN's or a wildcard based value that will allow the lambda to read the secrets to establish connections. Provide the ARN pattern with the `repo_secret_arns` variable shown above.
+
+An example of creating the secrets would look something like this.
+
+``` terraform
+locals {
+ repo_name = "dataRepoName
+ repo_username = "dbUsername"
+ repo_password = "thePassword"
+}
+
+resource "aws_secretsmanager_secret" "repo_secret" {
+ name = "/cyral/${local.repo_name}/RepoCreds"
+ description = "Repository credentials (username and password)"
+ recovery_window_in_days = 0 # Use this when testing so it can easily be cleaned up and re-used
+}
+
+
+resource "aws_secretsmanager_secret_version" "repo_secret_version" {
+ secret_id = aws_secretsmanager_secret.repo_secret.id
+ secret_string = jsonencode(
+ {
+ username = local.repo_username,
+ password = local.repo_password,
+ }
+ )
+}
+```
+
+## Data Repo Scan Schedule (Event Bridge Rule)
+
+In order to create a scheduled scan you'll have to create an event bridge rule with the correct permissions. The following example is fairly straight forward:
+
+```terraform
+locals {
+ repo_name = "dataRepoName"
+ schedule = "cron(0 0/6 * * ? *)"
+}
+
+# Create the rule trigger/schedule
+
+resource "aws_cloudwatch_event_rule" "this" {
+ name = "${local.repo_name}-event-rule"
+ description = "Runs the Repo Crawler Lambda function as specified by the scheduled expression."
+ schedule_expression = local.schedule
+}
+
+# Point the rule at the lambda and provide the configuration
+
+resource "aws_cloudwatch_event_target" "this" {
+ rule = aws_cloudwatch_event_rule.this.name
+ arn = module.cyral_repo_crawler.repo_crawler_lambda_function_arn
+ input = jsonencode(
+ {
+ config = {
+ # See the section below for full configuration options
+ repo-name = local.repo_name
+ repo-creds-secret-arn = aws_secretsmanager_secret.repo_secret.arn # See secret in previous section
+ }
+ }
+ )
+}
+
+# Allow Event Bridge Rule to invoke the Lambda
+
+resource "aws_lambda_permission" "this" {
+ function_name = module.cyral_repo_crawler.repo_crawler_lambda_function_name
+ action = "lambda:InvokeFunction"
+ principal = "events.amazonaws.com"
+ source_arn = aws_cloudwatch_event_rule.this.arn
+}
+```
+
+### Full Configuration Options
+
+The only required configuration parameters are the `repo-name` and `repo-creds-secret-arn` however the full selection of configuration options is below. The majority of this information is pulled from the control plane and these config options are overrides. Default values are shown in other cases.
+
+```terraform
+resource "aws_cloudwatch_event_target" "this" {
+ rule = aws_cloudwatch_event_rule.this.name
+ arn = aws_lambda_function.this.arn
+ input = jsonencode(
+ config = {
+ repo-name = "Name of repo to crawl",
+ repo-type = "Override Repo Type",
+ repo-host = "Override Repo Host",
+ repo-port = "Override Repo Port",
+ repo-database = "Specify the DB to scan otherwise all are scanned. (only applicable to some repo types)",
+ repo-sample-size = 5,
+ repo-max-query-timeout = "0s",
+ repo-max-open-conns = 10,
+ repo-max-parallel-dbs = 0,
+ repo-max-concurrency = 0,
+ repo-include-paths = "*",
+ repo-exclude-paths = "*",
+ repo-creds-secret-arn = "ARN with credentials to the database"
+ repo-advanced = {
+ snowflake = {
+ account = "Account Name",
+ role = "Role",
+ warehouse = "Warehouse",
+ },
+ oracle = {
+ service-name = "Service name, Typically ORCL"
+ },
+ connection-string-args = "Additional arguemnts to provide to the connection string"
+ },
+ data-classification = true,
+ account-discovery = true,
+ }
+ )
+}
+```
+
+#### Path Include/Exclude
+
+You can provide an Include or Exclude type approach leveraging the `repo-include-paths` or `repo-exclude-paths` which supports a comma-separated list of glob patterns, in the format `database.schema.table`, which represent paths to include/exclude when crawling the database.
+
+#### Snowflake
+
+If you are going to crawl a snowflake repository you will need to provide the appropriate `repo-advanced` section.
+
+#### Oracle
+
+In order to crawl an Oracle repo you'll need to provide the appropriate `repo-advanced` section. Typically the service name is `ORCL`.
+
+#### Crawl Type
+
+By default both a classification and account crawl will happen. Either of these can be disabled if required.
diff --git a/README.md b/README.md
index c4ea968..8a964e7 100644
--- a/README.md
+++ b/README.md
@@ -6,21 +6,23 @@ This is a Terraform module to install the Cyral Repo Crawler as an AWS
Lambda function, including all of its dependencies such as IAM permissions,
a DynamoDB cache, etc.
-See the [examples](./examples) for usage details.
+Addtional resources will need to be created to trigger it with the correct parameters. Most importantly an Event Bridge rule with configuration.
+
+See the [Deployments](./DEPLOYMENT.md) for usage details.
## Requirements
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 0.14 |
-| [aws](#requirement\_aws) | ~> 4.0 |
+| [aws](#requirement\_aws) | >= 4.0, < 6.0.0 |
| [random](#requirement\_random) | ~> 3.1 |
## Providers
| Name | Version |
|------|---------|
-| [aws](#provider\_aws) | ~> 4.0 |
+| [aws](#provider\_aws) | >= 4.0, < 6.0.0 |
| [random](#provider\_random) | ~> 3.1 |
## Modules
@@ -31,16 +33,11 @@ No modules.
| Name | Type |
|------|------|
-| [aws_cloudwatch_event_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
-| [aws_cloudwatch_event_target.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
| [aws_dynamodb_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table) | resource |
| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_lambda_function.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |
-| [aws_lambda_permission.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_secretsmanager_secret.cyral_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
-| [aws_secretsmanager_secret.repo_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
| [aws_secretsmanager_secret_version.cyral_secret_version](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
-| [aws_secretsmanager_secret_version.repo_secret_version](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
| [aws_security_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [random_id.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
@@ -53,7 +50,6 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
-| [connection-string-args](#input\_connection-string-args) | Optional database connection string options in `key=value` format:
`opt1=val1`, `opt2=val2`, etc. Currently only works for PostgreSQL-like
repos (i.e. Redshift, Denodo, or PostgreSQL), where this list gets
serialized into a comma separated string. | `list(string)` | `[]` | no |
| [control\_plane\_grpc\_port](#input\_control\_plane\_grpc\_port) | The TCP/IP port for the Cyral Control Plane gRPC API (default: 443). | `number` | `443` | no |
| [control\_plane\_host](#input\_control\_plane\_host) | The host for the Cyral Control Plane API, e.g. tenant.app.cyral.com. | `string` | n/a | yes |
| [control\_plane\_rest\_port](#input\_control\_plane\_rest\_port) | The TCP/IP port for the Cyral Control Plane REST API. (default: 443) | `number` | `443` | no |
@@ -63,31 +59,10 @@ No modules.
| [cyral\_client\_secret](#input\_cyral\_client\_secret) | The client secret to connect to the Cyral API. This is REQUIRED if the
`cyral_secret_arn` variable is empty. | `string` | `""` | no |
| [cyral\_secret\_arn](#input\_cyral\_secret\_arn) | ARN of the entry in AWS Secrets Manager that stores the secret containing
the credentials for the Cyral API. Either this OR the `cyral_client_id` and
`cyral_client_secret` variables are REQUIRED. If empty, the
`cyral_client_id` and `cyral_client_secret` variables MUST both be
provided, and a new secret will be created in AWS Secrets Manager. | `string` | `""` | no |
| [dynamodb\_cache\_table\_name\_suffix](#input\_dynamodb\_cache\_table\_name\_suffix) | The suffix for the DynamoDB table name used for the classification cache.
The full table will be prefixed with the Lambda function name
(default: cyralRepoCrawlerCache). | `string` | `"cyralRepoCrawlerCache"` | no |
-| [enable\_account\_discovery](#input\_enable\_account\_discovery) | Configures the Crawler to run in account discovery mode, i.e., query and
discover all existing user accounts in the database. | `bool` | `true` | no |
-| [enable\_data\_classification](#input\_enable\_data\_classification) | Configures the Crawler to run in data classification mode, i.e., sample and
classify data according to a set of existing labels. | `bool` | `true` | no |
-| [oracle\_service](#input\_oracle\_service) | The Oracle service name. Omit if not configuring an Oracle repo. | `string` | `""` | no |
-| [repo\_database](#input\_repo\_database) | The database on the repository that the repo crawler will connect to. If
omitted, the crawler will attempt to connect to and crawl all databases
accessible on the server (crawler versions >= v0.9.0 only). | `string` | `""` | no |
-| [repo\_exclude\_paths](#input\_repo\_exclude\_paths) | A comma-separated list of glob patterns, in the format
`database.schema.table`, which represent paths to exclude when crawling
the database. If empty (default), no paths are excluded. | `string` | `""` | no |
-| [repo\_host](#input\_repo\_host) | The hostname or host address of the database instance. If omitted, the value will
be inferred from the Control Plane (crawler versions >= v0.9.0 only). | `string` | `""` | no |
-| [repo\_include\_paths](#input\_repo\_include\_paths) | A comma-separated list of glob patterns, in the format
`database.schema.table`, which represent paths to include when crawling
the database. If empty or * (default), all paths are included. | `string` | `"*"` | no |
-| [repo\_max\_concurrency](#input\_repo\_max\_concurrency) | Advanced option to configure the maximum number of concurrent query
goroutines. If zero, there is no limit. Applies on a per-database level.
Each database crawled in parallel will have its own set of concurrent
queries, bounded by this limit. If zero, there is no limit. | `number` | `0` | no |
-| [repo\_max\_open\_conns](#input\_repo\_max\_open\_conns) | Maximum number of open connections to the database. | `number` | `10` | no |
-| [repo\_max\_parallel\_dbs](#input\_repo\_max\_parallel\_dbs) | Advanced option to configure the maximum number of databases to crawl in
parallel. This only applies if sampling all databases on the server, i.e.
if the database is omitted. If zero, there is no limit. | `number` | `0` | no |
-| [repo\_name](#input\_repo\_name) | The repository name on the Cyral Control Plane. | `string` | n/a | yes |
-| [repo\_password](#input\_repo\_password) | The password to connect to the repository. This is REQUIRED if the
`repo_secret_arn` variable is empty. | `string` | `""` | no |
-| [repo\_port](#input\_repo\_port) | The port of the database service in the database instance. If omitted, the value
will be inferred from the Control Plane (crawler versions >= v0.9.0 only). | `number` | `null` | no |
-| [repo\_query\_timeout](#input\_repo\_query\_timeout) | The maximum time any query can take before being canceled, as a duration
string, e.g. 10s or 5m. If zero or negative, there is no timeout. | `string` | `"0s"` | no |
-| [repo\_sample\_size](#input\_repo\_sample\_size) | Number of rows to sample from each table. | `number` | `5` | no |
-| [repo\_secret\_arn](#input\_repo\_secret\_arn) | ARN of the entry in AWS Secrets Manager that stores the secret containing
the credentials to connect to the repository. Either this OR the
`repo_username` and `repo_password` variables are REQUIRED. If empty, the
`repo_username` and `repo_password` variables MUST both be provided, and a
new secret will be created in AWS Secrets Manager. | `string` | `""` | no |
-| [repo\_type](#input\_repo\_type) | The repository type on the Cyral Control Plane. If omitted, the value will
be inferred from the Control Plane (crawler versions >= v0.9.0 only). | `string` | `""` | no |
-| [repo\_username](#input\_repo\_username) | The username to connect to the repository. This is REQUIRED if the
`repo_secret_arn` variable is empty and there is no database user
mapped to the repository on the Control Plane. | `string` | `""` | no |
-| [schedule\_expression](#input\_schedule\_expression) | Schedule expression to invoke the repo crawler. The default value
represents a run schedule of every six hours. | `string` | `"cron(0 0/6 * * ? *)"` | no |
-| [snowflake\_account](#input\_snowflake\_account) | The Snowflake account. Omit if not configuring a Snowflake repo. | `string` | `""` | no |
-| [snowflake\_role](#input\_snowflake\_role) | The Snowflake role. Omit if not configuring a Snowflake repo. | `string` | `""` | no |
-| [snowflake\_warehouse](#input\_snowflake\_warehouse) | The Snowflake warehouse. Omit if not configuring a Snowflake repo. | `string` | `""` | no |
-| [subnet\_ids](#input\_subnet\_ids) | The subnets that the Repo Crawler Lambda function will be deployed to. All
subnets must be able to reach both the Cyral Control Plane and the database
being crawled. These subnets must also support communication with
CloudWatch and Secrets Manager, therefore outbound internet access is
likely required. | `list(string)` | n/a | yes |
+| [repo\_secret\_arns](#input\_repo\_secret\_arns) | Secret ARN's to provide get access for the lambda. | `list(string)` | n/a | yes |
+| [subnet\_ids](#input\_subnet\_ids) | The subnets that the Repo Crawler Lambda function will be deployed to. All
subnets must be able to reach both the Cyral Control Plane and the database
being crawled. These subnets must also support communication with
CloudWatch and Secrets Manager, therefore outbound internet access is
likely required. | `list(string)` |
[| no | | [timeout](#input\_timeout) | The timeout of the Repo Crawler Lambda function, in seconds. | `number` | `300` | no | -| [vpc\_id](#input\_vpc\_id) | The VPC the lambda will be attached to. | `string` | n/a | yes | +| [vpc\_id](#input\_vpc\_id) | The VPC the lambda will be attached to. | `string` | `""` | no | ## Outputs @@ -95,4 +70,5 @@ No modules. |------|-------------| | [repo\_crawler\_aws\_security\_group\_id](#output\_repo\_crawler\_aws\_security\_group\_id) | The Amazon Security Group ID of the Repo Crawler Lambda function. | | [repo\_crawler\_lambda\_function\_arn](#output\_repo\_crawler\_lambda\_function\_arn) | The Amazon Resource Name (ARN) of the Repo Crawler Lambda function. | +| [repo\_crawler\_lambda\_function\_name](#output\_repo\_crawler\_lambda\_function\_name) | n/a | \ No newline at end of file diff --git a/examples/full/main.tf b/examples/full/main.tf deleted file mode 100644 index e7aadff..0000000 --- a/examples/full/main.tf +++ /dev/null @@ -1,47 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 4.0" - } - random = { - source = "hashicorp/random" - version = "~> 3.1" - } - } -} - -module "cyral_repo_crawler" { - source = "cyralinc/repo-crawler/aws" - version = "~> 0.1" - crawler_version = "v0.11.1" - crawler_name = "cyral-repo-crawler" - control_plane_host = "example.cyral.com" - control_plane_rest_port = 443 - control_plane_grpc_port = 443 - repo_type = "sqlserver" - repo_name = "sqlserver-example" - repo_host = "sqlserver.example.com" - repo_port = 1433 - repo_database = "exampledb" - repo_sample_size = 5 - repo_max_open_conns = 10 - subnet_ids = ["subnet-example"] - vpc_id = "vpc-example" - timeout = 300 - schedule_expression = "cron(0 0/6 * * ? *)" - dynamodb_cache_table_name_suffix = "cyralRepoCrawlerCache" - enable_data_classification = true - enable_account_discovery = true - - # It is preferable to create your own secrets and pass them via the - # cyral_secret_arn and repo_secret_arn variables. This will allow you to - # avoid passing confidential values directly in the Terraform config. - cyral_client_id = "example_client_id" - cyral_client_secret = "exampleClientSecret" - repo_username = "exampleRepoUsername" - repo_password = "exampleRepoUsername" - # Prefer to use these instead of the client ID/secret/username/password above - #cyral_secret_arn = "arn:aws:secretsmanager:us-east-2:123456789012:secret:/cyral-repo-crawler-37b68aab3a5e55ad/CyralSecret-qwAGUT" - #repo_secret_arn = "arn:aws:secretsmanager:us-east-2:123456789012:secret:/cyral-repo-crawler-37b68aab3a5e55ad/RepoSecret-MovNKP" -} diff --git a/examples/oracle/main.tf b/examples/oracle/main.tf deleted file mode 100644 index 927cc8d..0000000 --- a/examples/oracle/main.tf +++ /dev/null @@ -1,35 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 4.0" - } - random = { - source = "hashicorp/random" - version = "~> 3.1" - } - } -} - -module "cyral_repo_crawler" { - source = "cyralinc/repo-crawler/aws" - version = "~> 0.1" - crawler_version = "v0.11.1" - control_plane_host = "example.cyral.com" - repo_type = "oracle" - repo_name = "oracle-example" - repo_host = "oracle.example.com" - repo_port = 1521 - repo_database = "exampledb" - subnet_ids = ["subnet-example"] - vpc_id = "vpc-example" - oracle_service = "XE" - - # It is preferable to create your own secrets and pass them via the - # cyral_secret_arn and repo_secret_arn variables. This will allow you to - # avoid passing confidential values directly in the Terraform config. - cyral_client_id = "example_client_id" - cyral_client_secret = "exampleClientSecret" - repo_username = "exampleRepoUsername" - repo_password = "exampleRepoUsername" -} diff --git a/examples/postgres/main.tf b/examples/postgres/main.tf deleted file mode 100644 index e6e7dd2..0000000 --- a/examples/postgres/main.tf +++ /dev/null @@ -1,35 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 4.0" - } - random = { - source = "hashicorp/random" - version = "~> 3.1" - } - } -} - -module "cyral_repo_crawler" { - source = "cyralinc/repo-crawler/aws" - version = "~> 0.1" - crawler_version = "v0.11.1" - control_plane_host = "example.cyral.com" - repo_type = "postgresql" - repo_name = "postgres-example" - repo_host = "postgres.example.com" - repo_port = 5432 - repo_database = "exampledb" - subnet_ids = ["subnet-example"] - vpc_id = "vpc-example" - connection-string-args = "sslmode=require" - - # It is preferable to create your own secrets and pass them via the - # cyral_secret_arn and repo_secret_arn variables. This will allow you to - # avoid passing confidential values directly in the Terraform config. - cyral_client_id = "example_client_id" - cyral_client_secret = "exampleClientSecret" - repo_username = "exampleRepoUsername" - repo_password = "exampleRepoUsername" -} diff --git a/examples/simple/main.tf b/examples/simple/main.tf deleted file mode 100644 index b53f8a7..0000000 --- a/examples/simple/main.tf +++ /dev/null @@ -1,34 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 4.0" - } - random = { - source = "hashicorp/random" - version = "~> 3.1" - } - } -} - -module "cyral_repo_crawler" { - source = "cyralinc/repo-crawler/aws" - version = "~> 0.1" - crawler_version = "v0.11.1" - control_plane_host = "example.cyral.com" - repo_type = "sqlserver" - repo_name = "sqlserver-example" - repo_host = "sqlserver.example.com" - repo_port = 1433 - repo_database = "exampledb" - subnet_ids = ["subnet-example"] - vpc_id = "vpc-example" - - # It is preferable to create your own secrets and pass them via the - # cyral_secret_arn and repo_secret_arn variables. This will allow you to - # avoid passing confidential values directly in the Terraform config. - cyral_client_id = "example_client_id" - cyral_client_secret = "exampleClientSecret" - repo_username = "exampleRepoUsername" - repo_password = "exampleRepoUsername" -} diff --git a/examples/snowflake/main.tf b/examples/snowflake/main.tf deleted file mode 100644 index c642d15..0000000 --- a/examples/snowflake/main.tf +++ /dev/null @@ -1,37 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 4.0" - } - random = { - source = "hashicorp/random" - version = "~> 3.1" - } - } -} - -module "cyral_repo_crawler" { - source = "cyralinc/repo-crawler/aws" - version = "~> 0.1" - crawler_version = "v0.11.1" - control_plane_host = "example.cyral.com" - repo_type = "snowflake" - repo_name = "snowflake-example" - repo_host = "snowflake.example.com" - repo_port = 443 - repo_database = "exampledb" - subnet_ids = ["subnet-example"] - vpc_id = "vpc-example" - snowflake_account = "example-account" - snowflake_role = "example-role" - snowflake_warehouse = "example-warehouse" - - # It is preferable to create your own secrets and pass them via the - # cyral_secret_arn and repo_secret_arn variables. This will allow you to - # avoid passing confidential values directly in the Terraform config. - cyral_client_id = "example_client_id" - cyral_client_secret = "exampleClientSecret" - repo_username = "exampleRepoUsername" - repo_password = "exampleRepoUsername" -} diff --git a/main.tf b/main.tf index 5dfb040..ba6e3e1 100644 --- a/main.tf +++ b/main.tf @@ -16,7 +16,6 @@ locals { function_name = var.crawler_name != "" ? var.crawler_name : "cyral-repo-crawler-${random_id.this.hex}" dynamodb_cache_table_name = "${local.function_name}-${var.dynamodb_cache_table_name_suffix}" cyral_secret_arn = var.cyral_secret_arn != "" ? var.cyral_secret_arn : aws_secretsmanager_secret.cyral_secret[0].arn - repo_secret_arn = var.repo_secret_arn != "" ? var.repo_secret_arn : aws_secretsmanager_secret.repo_secret[0].arn } data "aws_partition" "current" {} @@ -41,10 +40,7 @@ data "aws_iam_policy_document" "execution_policy" { statement { actions = ["secretsmanager:GetSecretValue"] effect = "Allow" - resources = [ - local.cyral_secret_arn, - local.repo_secret_arn, - ] + resources = concat([local.cyral_secret_arn],var.repo_secret_arns) } # Allows access to write CloudWatch logs. @@ -115,6 +111,7 @@ resource "aws_iam_role" "this" { } resource "aws_security_group" "this" { + count = length(var.vpc_id) > 0 ? 1 : 0 name = local.function_name description = "Cyral Repo Crawler security group" vpc_id = var.vpc_id @@ -133,11 +130,7 @@ resource "aws_secretsmanager_secret" "cyral_secret" { description = "Cyral API credentials (client ID and secret)" } -resource "aws_secretsmanager_secret" "repo_secret" { - count = var.repo_secret_arn != "" ? 0 : 1 - name = "/${local.function_name}/RepoSecret" - description = "Repository credentials (username and password)" -} + resource "aws_secretsmanager_secret_version" "cyral_secret_version" { count = var.cyral_secret_arn != "" ? 0 : 1 @@ -150,17 +143,6 @@ resource "aws_secretsmanager_secret_version" "cyral_secret_version" { ) } -resource "aws_secretsmanager_secret_version" "repo_secret_version" { - count = var.repo_secret_arn != "" ? 0 : 1 - secret_id = aws_secretsmanager_secret.repo_secret[0].id - secret_string = jsonencode( - { - username = var.repo_username, - password = var.repo_password, - } - ) -} - resource "aws_lambda_function" "this" { function_name = local.function_name role = aws_iam_role.this.arn @@ -170,9 +152,12 @@ resource "aws_lambda_function" "this" { runtime = "provided.al2" handler = "bootstrap" - vpc_config { - security_group_ids = [aws_security_group.this.id] - subnet_ids = var.subnet_ids + dynamic vpc_config { + for_each = length(var.vpc_id) > 0 ? [1] : [] + content { + security_group_ids = [aws_security_group.this[0].id] + subnet_ids = var.subnet_ids + } } environment { @@ -199,52 +184,3 @@ resource "aws_dynamodb_table" "this" { } } -resource "aws_cloudwatch_event_rule" "this" { - name = "${local.function_name}-event-rule" - description = "Runs the Repo Crawler Lambda function as specified by the scheduled expression." - schedule_expression = var.schedule_expression -} - -resource "aws_cloudwatch_event_target" "this" { - rule = aws_cloudwatch_event_rule.this.name - arn = aws_lambda_function.this.arn - input = jsonencode( - { - config = { - repo-name = var.repo_name, - repo-type = var.repo_type, - repo-host = var.repo_host, - repo-port = var.repo_port, - repo-database = var.repo_database, - repo-sample-size = var.repo_sample_size, - repo-max-query-timeout = var.repo_query_timeout, - repo-max-open-conns = var.repo_max_open_conns, - repo-max-parallel-dbs = var.repo_max_parallel_dbs, - repo-max-concurrency = var.repo_max_concurrency, - repo-include-paths = var.repo_include_paths, - repo-exclude-paths = var.repo_exclude_paths, - repo-creds-secret-arn = local.repo_secret_arn - repo-advanced = { - snowflake = { - account = var.snowflake_account, - role = var.snowflake_role, - warehouse = var.snowflake_warehouse, - }, - oracle = { - service-name = var.oracle_service - }, - connection-string-args = var.connection-string-args - }, - data-classification = var.enable_data_classification, - account-discovery = var.enable_account_discovery, - } - } - ) -} - -resource "aws_lambda_permission" "this" { - function_name = aws_lambda_function.this.function_name - action = "lambda:InvokeFunction" - principal = "events.amazonaws.com" - source_arn = aws_cloudwatch_event_rule.this.arn -} diff --git a/outputs.tf b/outputs.tf index 882d2e8..b915e5e 100644 --- a/outputs.tf +++ b/outputs.tf @@ -3,7 +3,11 @@ output "repo_crawler_lambda_function_arn" { description = "The Amazon Resource Name (ARN) of the Repo Crawler Lambda function." } +output "repo_crawler_lambda_function_name" { + value = aws_lambda_function.this.function_name +} + output "repo_crawler_aws_security_group_id" { - value = aws_security_group.this.id + value = length(var.vpc_id) > 0 ? aws_security_group.this[0].id : null description = "The Amazon Security Group ID of the Repo Crawler Lambda function." } diff --git a/variables.tf b/variables.tf index b91dea0..3bebf9d 100644 --- a/variables.tf +++ b/variables.tf @@ -28,6 +28,12 @@ variable "cyral_secret_arn" { default = "" } +variable "repo_secret_arns" { + type = list(string) + description = "Secret ARN's to provide get access for the lambda." + +} + variable "cyral_client_id" { type = string description = <
""
]