Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions Examples/database_onboarding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Database Onboarding

This terraform takes a few simple parameters and then does the following

1. Create Postgres RDS DB
1. Inject sample data and install masking
1. Configure the data repo and access rules
1. Configure mapping and masking policy
197 changes: 197 additions & 0 deletions Examples/database_onboarding/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
provider "cyral" {
client_id = var.cyral_client_id
client_secret = var.cyral_client_secret
control_plane = var.cyral_control_plane
}

locals {
db_name = "test_data"
sidecar_name = var.sidecar_name
idp_name = "Okta-Sales"
repo_name = "example-tf-repo"

pg_listener_port = 5435
pg_listener_id = cyral_sidecar_listener.pg.id
db_login_name = "postgres"

sidecar_host = var.sidecar_host

database_credentials = {
username = "postgres"
password = random_password.db_password.result
}
}

# Get existing Sidecar
data "cyral_sidecar_id" "this" {
sidecar_name = local.sidecar_name
}

# Get existing Okta integration
data "cyral_integration_idp" "okta" {
display_name = local.idp_name
}

# Generate password for database
resource "random_password" "db_password" {
length = 16
special = true
override_special = "_%!"
}


# Build PG RDS Instance
resource "aws_db_instance" "postgres" {
identifier = local.repo_name
instance_class = "db.t3.micro"
engine = "postgres"
allocated_storage = 20
storage_type = "gp2"
username = local.database_credentials.username
password = random_password.db_password.result
db_name = local.db_name
backup_retention_period = 0
skip_final_snapshot = true
}

# Install masking and inject data
resource "null_resource" "init_db" {
depends_on = [aws_db_instance.postgres, cyral_repository_binding.pg, cyral_repository_conf_auth.pg, cyral_repository_conf_analysis.this]

provisioner "local-exec" {
command = <<EOF
psql -h ${local.sidecar_host} -U "${local.db_login_name}" -p ${local.pg_listener_port} -c "cyral install mask;"
echo "
CREATE TABLE customer_billing (
first_name VARCHAR(50),
last_name VARCHAR(50),
address VARCHAR(100),
ccn VARCHAR(16),
exp_date DATE
);

INSERT INTO customer_billing (first_name, last_name, address, ccn, exp_date)
VALUES
('John', 'Doe', '123 Main St, Anytown, USA', '1234567890123456', '2025-12-31'),
('Jane', 'Smith', '456 Elm St, Otherville, USA', '9876543210987654', '2024-09-30'),
('Alice', 'Johnson', '789 Oak St, Anycity, USA', '4567890123456789', '2026-06-30'),
('Bob', 'Williams', '101 Pine St, Someplace, USA', '5678901234567890', '2023-03-15'),
('Emma', 'Brown', '555 Cedar St, Elsewhere, USA', '3456789012345678', '2027-01-01');
" | psql -h ${local.sidecar_host} -U ${local.db_login_name} -p ${local.pg_listener_port}
EOF
environment = {
PGPASSWORD = random_password.db_password.result

}
}
}

# Create Data Repo for RDS Instance
resource "cyral_repository" "pg" {
name = local.repo_name
type = "postgresql"

repo_node {
host = aws_db_instance.postgres.address
port = 5432
}
}

# Create the listner (open port) on sidecar
resource "cyral_sidecar_listener" "pg" {
sidecar_id = data.cyral_sidecar_id.this.id
repo_types = ["postgresql"]
network_address {
port = local.pg_listener_port
}
}
# Bindind the data repo to the sidecar
resource "cyral_repository_binding" "pg" {
sidecar_id = data.cyral_sidecar_id.this.id
repository_id = cyral_repository.pg.id
listener_binding {
listener_id = cyral_sidecar_listener.pg.listener_id
}
}

# Configure authentication to allow the IDP and native authentication
resource "cyral_repository_conf_auth" "pg" {
repository_id = cyral_repository.pg.id
identity_provider = data.cyral_integration_idp.okta.idp_list[0].alias
allow_native_auth = true
repo_tls = "enable"
}

# Enable Data Access Portal
resource "cyral_repository_access_gateway" "this" {
repository_id = cyral_repository.pg.id
sidecar_id = data.cyral_sidecar_id.this.id
binding_id = cyral_repository_binding.pg.binding_id
}

# Enable masking and rewrites
resource "cyral_repository_conf_analysis" "this" {
repository_id = cyral_repository.pg.id
enable_dataset_rewrites = true
enable_data_masking = true
}

# Allow Nancy Access to the repo using the postgres user
resource "cyral_repository_access_rules" "this" {
repository_id = cyral_repository.pg.id
user_account_id = cyral_repository_user_account.my_user_account.user_account_id

rule {
identity {
type = "username"
name = "nancy.drew@hhiu.us"
}
}
}

# Data Mapping for CCN to our table/field
resource "cyral_repository_datamap" "ccn_map" {
repository_id = cyral_repository.pg.id
mapping {
label = "CCN"
attributes = [ "public.customer_billing.ccn" ]
}
}

# Masking Policy to do a constant mask of CCN
resource "cyral_rego_policy_instance" "ccn_policy" {
name = "Mask-CCN"
category = "SECURITY"
description = "Apply null masking to any data labeled as CCN for all users"
template_id = "data-masking"
parameters = "{ \"maskType\": \"CONSTANT_MASK\", \"maskArguments\": [\"**MASKED**\"], \"labels\": [\"CCN\"] }"
enabled = true
scope {
repo_ids = [cyral_repository.pg.id]
}
}

# Create secret for database creds and user account creation
resource "aws_secretsmanager_secret" "my_repository_secret" {
name = join("", [
"/cyral/dbsecrets/",
cyral_repository.pg.name
])
recovery_window_in_days = 0
}

resource "aws_secretsmanager_secret_version" "my_repository_secret_version" {
secret_id = aws_secretsmanager_secret.my_repository_secret.id
secret_string = jsonencode(local.database_credentials)
}

# Add User to Data Repo
resource "cyral_repository_user_account" "my_user_account" {
repository_id = cyral_repository.pg.id
name = local.database_credentials.username
auth_scheme {
aws_secrets_manager {
secret_arn = aws_secretsmanager_secret.my_repository_secret.arn
}
}
}
23 changes: 23 additions & 0 deletions Examples/database_onboarding/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
variable "cyral_control_plane" {
type = string
description = "Cyral Control Plane in the format <host>:<port>, e.g. tenant.cyral.com:443"
}

variable "cyral_client_id" {
type = string
description = "Cyral service account client ID"
}

variable "cyral_client_secret" {
type = string
description = "Cyral service account client secret"
}

variable "sidecar_host" {
type = string
description = "Host entry to access via the sidecartf taint "

}
variable "sidecar_name" {
type = string
}
15 changes: 15 additions & 0 deletions Examples/database_onboarding/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
cyral = {
source = "cyralinc/cyral"
version = ">= 4.9.0"
}
random = {
version = "~> 3.1"
}
}
}