Forseti Sicherheit Cheat Blatt
Überblick
Forseti Security ist ein Open-Source-Sicherheitstoolkit für Google Cloud Platform (GCP), das umfassende Sicherheitsüberwachung, politische Durchsetzung und Compliance-Management bietet. Ursprünglich von Google entwickelt, hilft Forseti Security Organisationen, Sicherheit in ihren GCP-Umgebungen durch automatisiertes Scannen, politische Validierung und Echtzeitüberwachung zu erhalten. Die Plattform bietet Bestandsverwaltung, politische Durchsetzung und Verstöße, die für die Aufrechterhaltung einer sicheren und konformen Cloud-Infrastruktur unerlässlich sind.
RECHT Key Features: Echtzeit-Inventar-Scanning, Policy-forcement Engine, Compliance-Monitoring, Sicherheitsverletzungserkennung, automatisierte Abhilfe, Multi-Projekt-Unterstützung, Custom-Regel-Engine und Integration mit Cloud Security Command Center.
Installation und Inbetriebnahme
Voraussetzungen und Umweltschutz
```bash
System requirements check
echo "Checking system requirements for Forseti Security..."
Check Python installation (Python 3.6+ required)
if command -v python3 &> /dev/null; then python_version=$(python3 --version | awk '{print $2}') echo "✅ Python found: $python_version" else echo "❌ Python not found. Installing Python 3..." sudo apt update sudo apt install -y python3 python3-pip python3-venv fi
Check gcloud CLI installation
if command -v gcloud &> /dev/null; then gcloud_version=$(gcloud --version | head -n1) echo "✅ Google Cloud CLI found: $gcloud_version" else echo "❌ Google Cloud CLI not found. Installing gcloud..." curl https://sdk.cloud.google.com | bash exec -l $SHELL gcloud init fi
Check Terraform installation (for infrastructure setup)
if command -v terraform &> /dev/null; then terraform_version=$(terraform --version | head -n1) echo "✅ Terraform found: $terraform_version" else echo "❌ Terraform not found. Installing Terraform..." | wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg | echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update && sudo apt install terraform fi
Check Docker installation (for containerized deployment)
if command -v docker &> /dev/null; then docker_version=$(docker --version) echo "✅ Docker found: $docker_version" else echo "❌ Docker not found. Installing Docker..." curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker $USER fi
Verify installations
echo "Verifying installations..." python3 --version gcloud --version terraform --version docker --version
echo "Prerequisites check completed" ```_
GCP Projektaufbau und Authentifizierung
```bash
Set up GCP project for Forseti Security
export PROJECT_ID="your-forseti-project" export ORGANIZATION_ID="your-organization-id" export BILLING_ACCOUNT="your-billing-account"
Authenticate with Google Cloud
gcloud auth login gcloud auth application-default login
Create or select project
gcloud projects create $PROJECT_ID --organization=$ORGANIZATION_ID gcloud config set project $PROJECT_ID
Link billing account
gcloud billing projects link $PROJECT_ID --billing-account=$BILLING_ACCOUNT
Enable required APIs
echo "Enabling required GCP APIs..." gcloud services enable cloudasset.googleapis.com gcloud services enable cloudresourcemanager.googleapis.com gcloud services enable compute.googleapis.com gcloud services enable container.googleapis.com gcloud services enable iam.googleapis.com gcloud services enable logging.googleapis.com gcloud services enable monitoring.googleapis.com gcloud services enable securitycenter.googleapis.com gcloud services enable sql-component.googleapis.com gcloud services enable storage-api.googleapis.com gcloud services enable storage-component.googleapis.com
Wait for APIs to be enabled
echo "Waiting for APIs to be enabled..." sleep 30
Verify API enablement
gcloud services list --enabled --filter="name:cloudasset.googleapis.com OR name:cloudresourcemanager.googleapis.com"
Create Forseti service account
gcloud iam service-accounts create forseti-security \ --display-name="Forseti Security Service Account" \ --description="Service account for Forseti Security operations"
Get service account email
export FORSETI_SA_EMAIL="forseti-security@${PROJECT_ID}.iam.gserviceaccount.com"
Grant necessary permissions to Forseti service account
echo "Granting permissions to Forseti service account..."
Organization-level permissions
gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \ --member="serviceAccount:$FORSETI_SA_EMAIL" \ --role="roles/browser"
gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \ --member="serviceAccount:$FORSETI_SA_EMAIL" \ --role="roles/cloudasset.viewer"
gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \ --member="serviceAccount:$FORSETI_SA_EMAIL" \ --role="roles/iam.securityReviewer"
gcloud organizations add-iam-policy-binding $ORGANIZATION_ID \ --member="serviceAccount:$FORSETI_SA_EMAIL" \ --role="roles/securitycenter.findingsEditor"
Project-level permissions
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$FORSETI_SA_EMAIL" \ --role="roles/cloudsql.client"
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$FORSETI_SA_EMAIL" \ --role="roles/compute.instanceAdmin"
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$FORSETI_SA_EMAIL" \ --role="roles/storage.objectAdmin"
Create and download service account key
gcloud iam service-accounts keys create forseti-security-key.json \ --iam-account=$FORSETI_SA_EMAIL
echo "GCP project setup completed" echo "Service account email: $FORSETI_SA_EMAIL" echo "Service account key saved to: forseti-security-key.json" ```_
Infrastruktur Bereitstellung
```bash
Create Terraform configuration for Forseti Security infrastructure
mkdir -p forseti-terraform cd forseti-terraform
Create main Terraform configuration
cat > main.tf << 'EOF' terraform { required_version = ">= 0.14" required_providers { google = { source = "hashicorp/google" version = "~> 4.0" } google-beta = { source = "hashicorp/google-beta" version = "~> 4.0" } } }
provider "google" { project = var.project_id region = var.region zone = var.zone }
provider "google-beta" { project = var.project_id region = var.region zone = var.zone }
Variables
variable "project_id" { description = "GCP Project ID" type = string }
variable "organization_id" { description = "GCP Organization ID" type = string }
variable "region" { description = "GCP Region" type = string default = "us-central1" }
variable "zone" { description = "GCP Zone" type = string default = "us-central1-a" }
variable "forseti_version" { description = "Forseti Security version" type = string default = "v2.25.1" }
VPC Network for Forseti
resource "google_compute_network" "forseti_network" { name = "forseti-security-network" auto_create_subnetworks = false description = "VPC network for Forseti Security" }
resource "google_compute_subnetwork" "forseti_subnetwork" { name = "forseti-security-subnetwork" ip_cidr_range = "10.0.0.0/24" region = var.region network = google_compute_network.forseti_network.id description = "Subnetwork for Forseti Security" }
Firewall rules
resource "google_compute_firewall" "forseti_server_allow_grpc" { name = "forseti-server-allow-grpc" network = google_compute_network.forseti_network.name
allow { protocol = "tcp" ports = ["50051"] }
source_ranges = ["10.0.0.0/24"] target_tags = ["forseti-server"] description = "Allow gRPC communication to Forseti server" }
resource "google_compute_firewall" "forseti_allow_ssh" { name = "forseti-allow-ssh" network = google_compute_network.forseti_network.name
allow { protocol = "tcp" ports = ["22"] }
source_ranges = ["0.0.0.0/0"] target_tags = ["forseti-security"] description = "Allow SSH access to Forseti instances" }
Cloud SQL instance for Forseti database
resource "google_sql_database_instance" "forseti_database" { name = "forseti-security-db" database_version = "MYSQL_8_0" region = var.region deletion_protection = false
settings { tier = "db-n1-standard-1" activation_policy = "ALWAYS" availability_type = "ZONAL" backup_configuration { enabled = true start_time = "03:00" location = var.region binary_log_enabled = true transaction_log_retention_days = 7 }
database_flags {
name = "slow_query_log"
value = "on"
}
ip_configuration {
ipv4_enabled = true
private_network = google_compute_network.forseti_network.id
require_ssl = true
authorized_networks {
name = "forseti-subnetwork"
value = "10.0.0.0/24"
}
}
maintenance_window {
day = 7
hour = 3
update_track = "stable"
}
}
depends_on = [google_service_networking_connection.private_vpc_connection] }
Private service connection for Cloud SQL
resource "google_compute_global_address" "private_ip_address" { name = "forseti-private-ip-address" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 network = google_compute_network.forseti_network.id }
resource "google_service_networking_connection" "private_vpc_connection" { network = google_compute_network.forseti_network.id service = "servicenetworking.googleapis.com" reserved_peering_ranges = [google_compute_global_address.private_ip_address.name] }
Forseti database
resource "google_sql_database" "forseti_database" { name = "forseti_security" instance = google_sql_database_instance.forseti_database.name }
Forseti database user
resource "google_sql_user" "forseti_user" { name = "forseti_security_user" instance = google_sql_database_instance.forseti_database.name password = random_password.forseti_db_password.result }
resource "random_password" "forseti_db_password" { length = 16 special = true }
Cloud Storage bucket for Forseti
resource "google_storage_bucket" "forseti_server_bucket" { name = "${var.project_id}-forseti-security-bucket" location = var.region force_destroy = true
uniform_bucket_level_access = true
versioning { enabled = true }
lifecycle_rule { condition { age = 30 } action { type = "Delete" } } }
Forseti Server VM instance
resource "google_compute_instance" "forseti_server" { name = "forseti-security-server" machine_type = "n1-standard-2" zone = var.zone
tags = ["forseti-server", "forseti-security"]
boot_disk { initialize_params { image = "ubuntu-os-cloud/ubuntu-2004-lts" size = 50 type = "pd-standard" } }
network_interface { network = google_compute_network.forseti_network.name subnetwork = google_compute_subnetwork.forseti_subnetwork.name
access_config {
// Ephemeral public IP
}
}
service_account { email = google_service_account.forseti_server_sa.email scopes = ["cloud-platform"] }
metadata = { enable-oslogin = "TRUE" }
metadata_startup_script = templatefile("${path.module}/startup-script.sh", { project_id = var.project_id forseti_version = var.forseti_version db_host = google_sql_database_instance.forseti_database.private_ip_address db_name = google_sql_database.forseti_database.name db_user = google_sql_user.forseti_user.name db_password = google_sql_user.forseti_user.password bucket_name = google_storage_bucket.forseti_server_bucket.name organization_id = var.organization_id })
depends_on = [ google_sql_database_instance.forseti_database, google_storage_bucket.forseti_server_bucket ] }
Forseti Client VM instance
resource "google_compute_instance" "forseti_client" { name = "forseti-security-client" machine_type = "n1-standard-1" zone = var.zone
tags = ["forseti-client", "forseti-security"]
boot_disk { initialize_params { image = "ubuntu-os-cloud/ubuntu-2004-lts" size = 30 type = "pd-standard" } }
network_interface { network = google_compute_network.forseti_network.name subnetwork = google_compute_subnetwork.forseti_subnetwork.name
access_config {
// Ephemeral public IP
}
}
service_account { email = google_service_account.forseti_client_sa.email scopes = ["cloud-platform"] }
metadata = { enable-oslogin = "TRUE" }
metadata_startup_script = templatefile("${path.module}/client-startup-script.sh", { project_id = var.project_id forseti_version = var.forseti_version server_ip = google_compute_instance.forseti_server.network_interface[0].network_ip }) }
Service accounts
resource "google_service_account" "forseti_server_sa" { account_id = "forseti-server-gcp-sa" display_name = "Forseti Server Service Account" description = "Service account for Forseti Security server" }
resource "google_service_account" "forseti_client_sa" { account_id = "forseti-client-gcp-sa" display_name = "Forseti Client Service Account" description = "Service account for Forseti Security client" }
IAM bindings for Forseti server service account
resource "google_organization_iam_member" "forseti_server_browser" { org_id = var.organization_id role = "roles/browser" member = "serviceAccount:${google_service_account.forseti_server_sa.email}" }
resource "google_organization_iam_member" "forseti_server_cloudasset_viewer" { org_id = var.organization_id role = "roles/cloudasset.viewer" member = "serviceAccount:${google_service_account.forseti_server_sa.email}" }
resource "google_organization_iam_member" "forseti_server_security_reviewer" { org_id = var.organization_id role = "roles/iam.securityReviewer" member = "serviceAccount:${google_service_account.forseti_server_sa.email}" }
resource "google_organization_iam_member" "forseti_server_security_center" { org_id = var.organization_id role = "roles/securitycenter.findingsEditor" member = "serviceAccount:${google_service_account.forseti_server_sa.email}" }
Project-level IAM bindings
resource "google_project_iam_member" "forseti_server_cloudsql_client" { project = var.project_id role = "roles/cloudsql.client" member = "serviceAccount:${google_service_account.forseti_server_sa.email}" }
resource "google_project_iam_member" "forseti_server_storage_admin" { project = var.project_id role = "roles/storage.objectAdmin" member = "serviceAccount:${google_service_account.forseti_server_sa.email}" }
Outputs
output "forseti_server_ip" { description = "Internal IP address of Forseti server" value = google_compute_instance.forseti_server.network_interface[0].network_ip }
output "forseti_server_external_ip" { description = "External IP address of Forseti server" value = google_compute_instance.forseti_server.network_interface[0].access_config[0].nat_ip }
output "forseti_client_ip" { description = "Internal IP address of Forseti client" value = google_compute_instance.forseti_client.network_interface[0].network_ip }
output "forseti_database_ip" { description = "Private IP address of Forseti database" value = google_sql_database_instance.forseti_database.private_ip_address }
output "forseti_bucket_name" { description = "Name of Forseti storage bucket" value = google_storage_bucket.forseti_server_bucket.name }
output "forseti_server_sa_email" { description = "Email of Forseti server service account" value = google_service_account.forseti_server_sa.email } EOF
Create startup script for Forseti server
cat > startup-script.sh << 'EOF'
!/bin/bash
Forseti Server Installation Script
set -e
Variables from Terraform
PROJECT_ID="${project_id}" FORSETI_VERSION="${forseti_version}" DB_HOST="${db_host}" DB_NAME="${db_name}" DB_USER="${db_user}" DB_PASSWORD="${db_password}" BUCKET_NAME="${bucket_name}" ORGANIZATION_ID="${organization_id}"
Update system
apt-get update apt-get install -y python3 python3-pip python3-venv git mysql-client
Create forseti user
useradd -m -s /bin/bash forseti usermod -aG sudo forseti
Install Forseti Security
cd /home/forseti git clone https://github.com/forseti-security/forseti-security.git cd forseti-security git checkout $FORSETI_VERSION
Create virtual environment
python3 -m venv forseti-env source forseti-env/bin/activate
Install dependencies
pip install --upgrade pip pip install -r requirements.txt pip install -e .
Create Forseti configuration directory
mkdir -p /home/forseti/forseti-security/configs
Create Forseti server configuration
cat > /home/forseti/forseti-security/configs/forseti_conf_server.yaml << EOFCONFIG global: # Database configuration db_host: $DB_HOST db_user: $DB_USER db_name: $DB_NAME db_password: $DB_PASSWORD
# GCS bucket for Forseti data
bucket_name: $BUCKET_NAME
# Email notification settings
email_recipient: admin@company.com
email_sender: forseti-noreply@$PROJECT_ID.iam.gserviceaccount.com
sendgrid_api_key: ""
# Organization and project settings
organization_id: $ORGANIZATION_ID
inventory: # Inventory configuration gcs_summary_path: gs://$BUCKET_NAME/inventory_summary.json
# Root resource to start inventory from
root_resource_id: $ORGANIZATION_ID
# Inventory modules to enable
api_quota_enabled: true
cai_enabled: true
scanner: # Scanner configuration enabled_scanners: - audit_logging - bigquery - blacklist - bucket_acl - cloudsql_acl - enabled_apis - firewall_rule - forwarding_rule - group - iam_policy - iap - instance_network_interface - ke_cluster - ke_node_pool - lien - location - log_sink - resource - service_account_key
# Scanner output path
output_path: gs://$BUCKET_NAME/scanner_violations
# Violation configs
rules_path: /home/forseti/forseti-security/rules
notifier: # Notification configuration enabled: true
# Notification channels
email_enabled: true
gcs_enabled: true
cscc_enabled: true
# CSCC (Cloud Security Command Center) settings
cscc_source_id: ""
# Violation summary
violation_summary_enabled: true
explain: # Explain configuration enabled: true
model: # Model configuration enabled: true
# Model location
model_location: gs://$BUCKET_NAME/model
EOFCONFIG
Set up database
mysql -h $DB_HOST -u $DB_USER -p$DB_PASSWORD $DB_NAME < install/gcp/scripts/create_forseti_tables.sql
Create systemd service for Forseti server
cat > /etc/systemd/system/forseti-server.service << EOFSERVICE [Unit] Description=Forseti Security Server After=network.target
[Service] Type=simple User=forseti Group=forseti WorkingDirectory=/home/forseti/forseti-security Environment=PATH=/home/forseti/forseti-security/forseti-env/bin ExecStart=/home/forseti/forseti-security/forseti-env/bin/python -m google.cloud.forseti.services.server --config_file_path=/home/forseti/forseti-security/configs/forseti_conf_server.yaml Restart=always RestartSec=10
[Install] WantedBy=multi-user.target EOFSERVICE
Set permissions
chown -R forseti:forseti /home/forseti chmod +x /home/forseti/forseti-security/forseti-env/bin/*
Enable and start Forseti server
systemctl daemon-reload systemctl enable forseti-server systemctl start forseti-server
Create log rotation
cat > /etc/logrotate.d/forseti << EOFLOGROTATE /var/log/forseti/*.log { daily missingok rotate 30 compress delaycompress notifempty create 644 forseti forseti postrotate systemctl reload forseti-server endscript } EOFLOGROTATE
echo "Forseti Security server installation completed" EOF
Create startup script for Forseti client
cat > client-startup-script.sh << 'EOF'
!/bin/bash
Forseti Client Installation Script
set -e
Variables from Terraform
PROJECT_ID="${project_id}" FORSETI_VERSION="${forseti_version}" SERVER_IP="${server_ip}"
Update system
apt-get update apt-get install -y python3 python3-pip python3-venv git
Create forseti user
useradd -m -s /bin/bash forseti usermod -aG sudo forseti
Install Forseti Security client
cd /home/forseti git clone https://github.com/forseti-security/forseti-security.git cd forseti-security git checkout $FORSETI_VERSION
Create virtual environment
python3 -m venv forseti-env source forseti-env/bin/activate
Install dependencies
pip install --upgrade pip pip install -r requirements.txt pip install -e .
Create Forseti client configuration
mkdir -p /home/forseti/forseti-security/configs
cat > /home/forseti/forseti-security/configs/forseti_conf_client.yaml << EOFCONFIG server_ip: $SERVER_IP server_port: 50051 EOFCONFIG
Set permissions
chown -R forseti:forseti /home/forseti
echo "Forseti Security client installation completed" EOF
Create terraform.tfvars file
cat > terraform.tfvars << EOF project_id = "$PROJECT_ID" organization_id = "$ORGANIZATION_ID" region = "us-central1" zone = "us-central1-a" forseti_version = "v2.25.1" EOF
Initialize and apply Terraform
terraform init terraform plan terraform apply -auto-approve
echo "Forseti Security infrastructure deployment completed" ```_
Einsatz von Docker
```bash
Create Docker Compose setup for Forseti Security
mkdir -p forseti-docker cd forseti-docker
Create Docker Compose file
cat > docker-compose.yml << 'EOF' version: '3.8'
services: # MySQL Database for Forseti forseti-db: image: mysql:8.0 container_name: forseti-mysql environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: forseti_security MYSQL_USER: forseti_security_user MYSQL_PASSWORD: forseti123 ports: - "3306:3306" volumes: - forseti_mysql_data:/var/lib/mysql - ./init-scripts:/docker-entrypoint-initdb.d networks: - forseti-network command: --default-authentication-plugin=mysql_native_password
# Forseti Security Server forseti-server: build: context: . dockerfile: Dockerfile.server container_name: forseti-server depends_on: - forseti-db environment: - FORSETI_DB_HOST=forseti-db - FORSETI_DB_PORT=3306 - FORSETI_DB_NAME=forseti_security - FORSETI_DB_USER=forseti_security_user - FORSETI_DB_PASSWORD=forseti123 - GOOGLE_APPLICATION_CREDENTIALS=/app/credentials/service-account.json - FORSETI_ORGANIZATION_ID=${ORGANIZATION_ID} - FORSETI_PROJECT_ID=${PROJECT_ID} ports: - "50051:50051" volumes: - ./config:/app/config - ./credentials:/app/credentials - ./rules:/app/rules - ./logs:/app/logs networks: - forseti-network
# Forseti Security Client forseti-client: build: context: . dockerfile: Dockerfile.client container_name: forseti-client depends_on: - forseti-server environment: - FORSETI_SERVER_HOST=forseti-server - FORSETI_SERVER_PORT=50051 - GOOGLE_APPLICATION_CREDENTIALS=/app/credentials/service-account.json volumes: - ./config:/app/config - ./credentials:/app/credentials - ./logs:/app/logs networks: - forseti-network stdin_open: true tty: true
volumes: forseti_mysql_data:
networks: forseti-network: driver: bridge EOF
Create Dockerfile for Forseti server
cat > Dockerfile.server << 'EOF' FROM python:3.8-slim
Install system dependencies
RUN apt-get update && apt-get install -y \ git \ mysql-client \ && rm -rf /var/lib/apt/lists/*
Create app directory
WORKDIR /app
Clone Forseti Security
RUN git clone https://github.com/forseti-security/forseti-security.git . RUN git checkout v2.25.1
Install Python dependencies
RUN pip install --upgrade pip RUN pip install -r requirements.txt RUN pip install -e .
Create necessary directories
RUN mkdir -p /app/config /app/credentials /app/rules /app/logs
Copy configuration files
COPY config/ /app/config/ COPY rules/ /app/rules/
Set permissions
RUN chmod +x /app/google/cloud/forseti/services/server.py
Expose gRPC port
EXPOSE 50051
Start Forseti server
CMD ["python", "-m", "google.cloud.forseti.services.server", "--config_file_path=/app/config/forseti_conf_server.yaml"] EOF
Create Dockerfile for Forseti client
cat > Dockerfile.client << 'EOF' FROM python:3.8-slim
Install system dependencies
RUN apt-get update && apt-get install -y \ git \ && rm -rf /var/lib/apt/lists/*
Create app directory
WORKDIR /app
Clone Forseti Security
RUN git clone https://github.com/forseti-security/forseti-security.git . RUN git checkout v2.25.1
Install Python dependencies
RUN pip install --upgrade pip RUN pip install -r requirements.txt RUN pip install -e .
Create necessary directories
RUN mkdir -p /app/config /app/credentials /app/logs
Copy configuration files
COPY config/ /app/config/
Start bash shell for interactive use
CMD ["/bin/bash"] EOF
Create configuration directory and files
mkdir -p config credentials rules logs init-scripts
Create Forseti server configuration
cat > config/forseti_conf_server.yaml << 'EOF' global: # Database configuration db_host: forseti-db db_user: forseti_security_user db_name: forseti_security db_password: forseti123
# Email notification settings
email_recipient: admin@company.com
email_sender: forseti-noreply@company.com
sendgrid_api_key: ""
# Organization and project settings
organization_id: "123456789012"
inventory: # Inventory configuration root_resource_id: "123456789012"
# Inventory modules to enable
api_quota_enabled: true
cai_enabled: true
scanner: # Scanner configuration enabled_scanners: - audit_logging - bigquery - blacklist - bucket_acl - cloudsql_acl - enabled_apis - firewall_rule - forwarding_rule - group - iam_policy - iap - instance_network_interface - ke_cluster - ke_node_pool - lien - location - log_sink - resource - service_account_key
# Violation configs
rules_path: /app/rules
notifier: # Notification configuration enabled: true
# Notification channels
email_enabled: true
gcs_enabled: false
cscc_enabled: false
# Violation summary
violation_summary_enabled: true
explain: # Explain configuration enabled: true
model: # Model configuration enabled: true EOF
Create Forseti client configuration
cat > config/forseti_conf_client.yaml << 'EOF' server_ip: forseti-server server_port: 50051 EOF
Create MySQL initialization script
cat > init-scripts/01-init-forseti.sql << 'EOF' -- Forseti Security Database Initialization
USE forseti_security;
-- Create tables for Forseti Security CREATE TABLE IF NOT EXISTS violations ( id BIGINT AUTO_INCREMENT PRIMARY KEY, resource_id VARCHAR(255), resource_type VARCHAR(255), rule_name VARCHAR(255), rule_index INT, violation_type VARCHAR(255), violation_data TEXT, resource_data TEXT, created_at_datetime TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
CREATE TABLE IF NOT EXISTS inventory ( id BIGINT AUTO_INCREMENT PRIMARY KEY, inventory_index_id BIGINT, inventory_type VARCHAR(255), resource_data TEXT, created_at_datetime TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
CREATE TABLE IF NOT EXISTS inventory_index ( id BIGINT AUTO_INCREMENT PRIMARY KEY, inventory_index_id BIGINT UNIQUE, completed_at_datetime TIMESTAMP, created_at_datetime TIMESTAMP DEFAULT CURRENT_TIMESTAMP, count_objects INT DEFAULT 0, schema_version VARCHAR(255) );
-- Insert sample data INSERT INTO inventory_index (inventory_index_id, completed_at_datetime, count_objects, schema_version) VALUES (1, NOW(), 0, '2.25.1');
COMMIT; EOF
Create sample rules directory
mkdir -p rules
Create sample security rules
cat > rules/firewall_rules.yaml << 'EOF' rules: - name: 'Firewall rule allows all traffic' mode: blacklist resource: - type: firewall_rule filters: - key: direction op: eq value: INGRESS - key: sourceRanges op: contains value: '0.0.0.0/0' - key: allowed.ports op: contains value: '' actions: - type: add_to_whitelist value: 'firewall-rule-' EOF
cat > rules/iam_rules.yaml << 'EOF' rules: - name: 'Service account has too many roles' mode: blacklist resource: - type: iam_policy filters: - key: bindings.members op: regex value: 'serviceAccount:.' - key: bindings.role op: regex value: 'roles/.' actions: - type: add_to_whitelist value: 'serviceAccount:@.iam.gserviceaccount.com' EOF
Create environment file
cat > .env << EOF PROJECT_ID=your-project-id ORGANIZATION_ID=your-organization-id EOF
Start Forseti with Docker Compose
echo "Starting Forseti Security with Docker Compose..." docker-compose up -d
Wait for services to start
echo "Waiting for services to start..." sleep 60
Check service status
docker-compose ps
Test connectivity
echo "Testing service connectivity..." docker-compose exec forseti-db mysql -u forseti_security_user -pforseti123 -e "SELECT 1" docker-compose logs forseti-server | tail -20
echo "Forseti Security Docker deployment completed" echo "Access Forseti server at: localhost:50051" echo "Connect to client: docker-compose exec forseti-client /bin/bash" ```_
Konfiguration und Regelverwaltung
Grundkonfiguration
```bash
Create Forseti configuration management script
cat > configure_forseti.sh << 'EOF'
!/bin/bash
Forseti Security Configuration Management
FORSETI_HOME=${FORSETI_HOME:-/home/forseti/forseti-security} CONFIG_DIR="$FORSETI_HOME/configs" RULES_DIR="$FORSETI_HOME/rules"
Create directories
mkdir -p "$CONFIG_DIR" "$RULES_DIR"
Function to configure inventory settings
configure_inventory() { echo "Configuring Forseti inventory settings..."
cat > "$CONFIG_DIR/inventory_config.yaml" << 'INVCONFIG'
Forseti Inventory Configuration
inventory: # Root resource configuration root_resource_id: "organizations/123456789012"
# Inventory modules
api_quota_enabled: true
cai_enabled: true
# Resource types to inventory
resource_types:
- organization
- folder
- project
- compute_instance
- compute_disk
- compute_network
- compute_subnetwork
- compute_firewall
- storage_bucket
- cloudsql_instance
- iam_policy
- service_account
- service_account_key
- bigquery_dataset
- bigquery_table
- kubernetes_cluster
- kubernetes_node_pool
# Inventory frequency (in seconds)
inventory_frequency: 3600
# Parallel processing
max_workers: 10
# Timeout settings
inventory_timeout: 1800
# Output settings
output_format: json
gcs_summary_path: gs://forseti-bucket/inventory_summary.json
INVCONFIG
echo "Inventory configuration completed"
}
Function to configure scanner settings
configure_scanner() { echo "Configuring Forseti scanner settings..."
cat > "$CONFIG_DIR/scanner_config.yaml" << 'SCANCONFIG'
Forseti Scanner Configuration
scanner: # Enabled scanners enabled_scanners: - audit_logging - bigquery - blacklist - bucket_acl - cloudsql_acl - enabled_apis - firewall_rule - forwarding_rule - group - iam_policy - iap - instance_network_interface - ke_cluster - ke_node_pool - lien - location - log_sink - resource - service_account_key
# Scanner frequency (in seconds)
scanner_frequency: 7200
# Output settings
output_path: gs://forseti-bucket/scanner_violations
# Violation retention (in days)
violation_retention_days: 30
# Scanner timeout (in seconds)
scanner_timeout: 3600
# Parallel processing
max_scanner_processes: 5
# Rules configuration
rules_path: /home/forseti/forseti-security/rules
# Whitelist configuration
whitelist_enabled: true
whitelist_path: /home/forseti/forseti-security/rules/whitelist.yaml
SCANCONFIG
echo "Scanner configuration completed"
}
Function to configure notifier settings
configure_notifier() { echo "Configuring Forseti notifier settings..."
cat > "$CONFIG_DIR/notifier_config.yaml" << 'NOTIFYCONFIG'
Forseti Notifier Configuration
notifier: # Notification enabled enabled: true
# Email notifications
email_enabled: true
email_recipient: security-team@company.com
email_sender: forseti-noreply@company.com
# SendGrid configuration
sendgrid_api_key: ""
# GCS notifications
gcs_enabled: true
gcs_path: gs://forseti-bucket/notifications
# Cloud Security Command Center
cscc_enabled: true
cscc_source_id: "organizations/123456789012/sources/1234567890123456789"
# Slack notifications
slack_enabled: false
slack_webhook_url: ""
# Notification frequency
notification_frequency: 86400
# Violation summary
violation_summary_enabled: true
# Notification filters
notification_filters:
- severity: HIGH
enabled: true
- severity: MEDIUM
enabled: true
- severity: LOW
enabled: false
# Template configuration
email_template_path: /home/forseti/forseti-security/templates/email_template.html
NOTIFYCONFIG
echo "Notifier configuration completed"
}
Function to configure explain settings
configure_explain() { echo "Configuring Forseti explain settings..."
cat > "$CONFIG_DIR/explain_config.yaml" << 'EXPLAINCONFIG'
Forseti Explain Configuration
explain: # Explain enabled enabled: true
# Explain timeout (in seconds)
explain_timeout: 300
# Maximum number of policies to explain
max_policies: 1000
# Output format
output_format: json
# Cache settings
cache_enabled: true
cache_ttl: 3600
# Explain frequency (in seconds)
explain_frequency: 21600
EXPLAINCONFIG
echo "Explain configuration completed"
}
Function to configure model settings
configure_model() { echo "Configuring Forseti model settings..."
cat > "$CONFIG_DIR/model_config.yaml" << 'MODELCONFIG'
Forseti Model Configuration
model: # Model enabled enabled: true
# Model location
model_location: gs://forseti-bucket/model
# Model timeout (in seconds)
model_timeout: 1800
# Model frequency (in seconds)
model_frequency: 3600
# Model retention (in days)
model_retention_days: 7
# Model verification
verify_policy_awesomeness: true
MODELCONFIG
echo "Model configuration completed"
}
Main configuration function
main() { echo "Starting Forseti Security configuration..."
configure_inventory
configure_scanner
configure_notifier
configure_explain
configure_model
# Set permissions
chmod -R 755 "$CONFIG_DIR"
echo "Forseti Security configuration completed successfully"
echo "Configuration files created in: $CONFIG_DIR"
}
Run configuration
main "$@" EOF
chmod +x configure_forseti.sh ./configure_forseti.sh ```_
Erstellung der Zollregel
```python
!/usr/bin/env python3
Forseti Security Custom Rule Creation
import yaml import json import os from datetime import datetime
class ForsetiRuleManager: """Manage Forseti Security custom rules"""
def __init__(self, rules_directory='/home/forseti/forseti-security/rules'):
self.rules_directory = rules_directory
self.ensure_rules_directory()
def ensure_rules_directory(self):
"""Ensure rules directory exists"""
os.makedirs(self.rules_directory, exist_ok=True)
def create_firewall_rules(self):
"""Create firewall security rules"""
firewall_rules = {
'rules': [
{
'name': 'Firewall allows all traffic from internet',
'mode': 'blacklist',
'resource': [{'type': 'firewall_rule'}],
'filters': [
{'key': 'direction', 'op': 'eq', 'value': 'INGRESS'},
{'key': 'sourceRanges', 'op': 'contains', 'value': '0.0.0.0/0'},
{'key': 'allowed.ports', 'op': 'contains', 'value': '*'}
],
'actions': [
{'type': 'add_to_whitelist', 'value': 'firewall-rule-web-*'}
]
},
{
'name': 'Firewall allows SSH from internet',
'mode': 'blacklist',
'resource': [{'type': 'firewall_rule'}],
'filters': [
{'key': 'direction', 'op': 'eq', 'value': 'INGRESS'},
{'key': 'sourceRanges', 'op': 'contains', 'value': '0.0.0.0/0'},
{'key': 'allowed.ports', 'op': 'contains', 'value': '22'}
]
},
{
'name': 'Firewall allows RDP from internet',
'mode': 'blacklist',
'resource': [{'type': 'firewall_rule'}],
'filters': [
{'key': 'direction', 'op': 'eq', 'value': 'INGRESS'},
{'key': 'sourceRanges', 'op': 'contains', 'value': '0.0.0.0/0'},
{'key': 'allowed.ports', 'op': 'contains', 'value': '3389'}
]
}
]
}
with open(f"{self.rules_directory}/firewall_rules.yaml", 'w') as f:
yaml.dump(firewall_rules, f, default_flow_style=False)
print("Firewall rules created successfully")
def create_iam_rules(self):
"""Create IAM security rules"""
iam_rules = {
'rules': [
{
'name': 'Service account has owner role',
'mode': 'blacklist',
'resource': [{'type': 'iam_policy'}],
'filters': [
{'key': 'bindings.members', 'op': 'regex', 'value': 'serviceAccount:.*'},
{'key': 'bindings.role', 'op': 'eq', 'value': 'roles/owner'}
]
},
{
'name': 'User has primitive roles',
'mode': 'blacklist',
'resource': [{'type': 'iam_policy'}],
'filters': [
{'key': 'bindings.members', 'op': 'regex', 'value': 'user:.*'},
| {'key': 'bindings.role', 'op': 'regex', 'value': 'roles/(owner | editor | viewer)'} | ], 'actions': [ {'type': 'add_to_whitelist', 'value': 'user:admin@company.com'} ] }, { 'name': 'Service account key is old', 'mode': 'blacklist', 'resource': [{'type': 'service_account_key'}], 'filters': [ {'key': 'validAfterTime', 'op': 'older_than', 'value': '90d'} ] } ] }
with open(f"{self.rules_directory}/iam_rules.yaml", 'w') as f:
yaml.dump(iam_rules, f, default_flow_style=False)
print("IAM rules created successfully")
def create_storage_rules(self):
"""Create Cloud Storage security rules"""
storage_rules = {
'rules': [
{
'name': 'Storage bucket is publicly readable',
'mode': 'blacklist',
'resource': [{'type': 'bucket_acl'}],
'filters': [
{'key': 'entity', 'op': 'eq', 'value': 'allUsers'},
{'key': 'role', 'op': 'eq', 'value': 'READER'}
],
'actions': [
{'type': 'add_to_whitelist', 'value': 'public-website-*'}
]
},
{
'name': 'Storage bucket is publicly writable',
'mode': 'blacklist',
'resource': [{'type': 'bucket_acl'}],
'filters': [
{'key': 'entity', 'op': 'eq', 'value': 'allUsers'},
{'key': 'role', 'op': 'eq', 'value': 'WRITER'}
]
},
{
'name': 'Storage bucket allows authenticated users',
'mode': 'blacklist',
'resource': [{'type': 'bucket_acl'}],
'filters': [
{'key': 'entity', 'op': 'eq', 'value': 'allAuthenticatedUsers'}
]
}
]
}
with open(f"{self.rules_directory}/storage_rules.yaml", 'w') as f:
yaml.dump(storage_rules, f, default_flow_style=False)
print("Storage rules created successfully")
def create_compute_rules(self):
"""Create Compute Engine security rules"""
compute_rules = {
'rules': [
{
'name': 'Instance has public IP',
'mode': 'blacklist',
'resource': [{'type': 'instance'}],
'filters': [
{'key': 'networkInterfaces.accessConfigs.type', 'op': 'eq', 'value': 'ONE_TO_ONE_NAT'}
],
'actions': [
{'type': 'add_to_whitelist', 'value': 'bastion-*'},
{'type': 'add_to_whitelist', 'value': 'web-*'}
]
},
{
'name': 'Instance allows HTTP traffic',
'mode': 'blacklist',
'resource': [{'type': 'instance'}],
'filters': [
{'key': 'tags.items', 'op': 'contains', 'value': 'http-server'}
]
},
{
'name': 'Instance has default service account',
'mode': 'blacklist',
'resource': [{'type': 'instance'}],
'filters': [
{'key': 'serviceAccounts.email', 'op': 'regex', 'value': '.*-compute@developer.gserviceaccount.com'}
]
}
]
}
with open(f"{self.rules_directory}/compute_rules.yaml", 'w') as f:
yaml.dump(compute_rules, f, default_flow_style=False)
print("Compute rules created successfully")
def create_cloudsql_rules(self):
"""Create Cloud SQL security rules"""
cloudsql_rules = {
'rules': [
{
'name': 'Cloud SQL instance allows public access',
'mode': 'blacklist',
'resource': [{'type': 'cloudsql_instance'}],
'filters': [
{'key': 'settings.ipConfiguration.authorizedNetworks.value', 'op': 'eq', 'value': '0.0.0.0/0'}
]
},
{
'name': 'Cloud SQL instance has SSL disabled',
'mode': 'blacklist',
'resource': [{'type': 'cloudsql_instance'}],
'filters': [
{'key': 'settings.ipConfiguration.requireSsl', 'op': 'eq', 'value': False}
]
},
{
'name': 'Cloud SQL instance has backup disabled',
'mode': 'blacklist',
'resource': [{'type': 'cloudsql_instance'}],
'filters': [
{'key': 'settings.backupConfiguration.enabled', 'op': 'eq', 'value': False}
]
}
]
}
with open(f"{self.rules_directory}/cloudsql_rules.yaml", 'w') as f:
yaml.dump(cloudsql_rules, f, default_flow_style=False)
print("Cloud SQL rules created successfully")
def create_kubernetes_rules(self):
"""Create Kubernetes security rules"""
kubernetes_rules = {
'rules': [
{
'name': 'GKE cluster has legacy ABAC enabled',
'mode': 'blacklist',
'resource': [{'type': 'ke_cluster'}],
'filters': [
{'key': 'legacyAbac.enabled', 'op': 'eq', 'value': True}
]
},
{
'name': 'GKE cluster has basic authentication enabled',
'mode': 'blacklist',
'resource': [{'type': 'ke_cluster'}],
'filters': [
{'key': 'masterAuth.username', 'op': 'ne', 'value': ''}
]
},
{
'name': 'GKE cluster has client certificate enabled',
'mode': 'blacklist',
'resource': [{'type': 'ke_cluster'}],
'filters': [
{'key': 'masterAuth.clientCertificateConfig.issueClientCertificate', 'op': 'eq', 'value': True}
]
},
{
'name': 'GKE node pool has legacy metadata endpoints enabled',
'mode': 'blacklist',
'resource': [{'type': 'ke_node_pool'}],
'filters': [
{'key': 'config.metadata.disable-legacy-endpoints', 'op': 'ne', 'value': 'true'}
]
}
]
}
with open(f"{self.rules_directory}/kubernetes_rules.yaml", 'w') as f:
yaml.dump(kubernetes_rules, f, default_flow_style=False)
print("Kubernetes rules created successfully")
def create_whitelist_rules(self):
"""Create whitelist configuration"""
whitelist_config = {
'whitelist': {
'firewall_rule': [
'firewall-rule-web-allow-80',
'firewall-rule-web-allow-443',
'firewall-rule-bastion-ssh'
],
'instance': [
'bastion-host-prod',
'web-server-prod-*'
],
'bucket_acl': [
'public-website-bucket',
'public-assets-bucket'
],
'iam_policy': [
'user:admin@company.com',
'serviceAccount:terraform@project.iam.gserviceaccount.com'
]
}
}
with open(f"{self.rules_directory}/whitelist.yaml", 'w') as f:
yaml.dump(whitelist_config, f, default_flow_style=False)
print("Whitelist configuration created successfully")
def create_custom_rule(self, rule_name, resource_type, filters, mode='blacklist', actions=None):
"""Create a custom rule"""
rule = {
'rules': [
{
'name': rule_name,
'mode': mode,
'resource': [{'type': resource_type}],
'filters': filters
}
]
}
if actions:
rule['rules'][0]['actions'] = actions
filename = f"{rule_name.lower().replace(' ', '_')}_rule.yaml"
with open(f"{self.rules_directory}/{filename}", 'w') as f:
yaml.dump(rule, f, default_flow_style=False)
print(f"Custom rule '{rule_name}' created successfully: {filename}")
def validate_rule(self, rule_file):
"""Validate rule syntax"""
try:
with open(rule_file, 'r') as f:
rule_data = yaml.safe_load(f)
# Basic validation
if 'rules' not in rule_data:
return False, "Missing 'rules' key"
for rule in rule_data['rules']:
required_keys = ['name', 'mode', 'resource', 'filters']
for key in required_keys:
if key not in rule:
return False, f"Missing required key: {key}"
# Validate mode
if rule['mode'] not in ['blacklist', 'whitelist']:
return False, f"Invalid mode: {rule['mode']}"
# Validate resource type
valid_types = [
'firewall_rule', 'instance', 'bucket_acl', 'iam_policy',
'service_account_key', 'cloudsql_instance', 'ke_cluster', 'ke_node_pool'
]
for resource in rule['resource']:
if resource['type'] not in valid_types:
return False, f"Invalid resource type: {resource['type']}"
return True, "Rule validation passed"
except Exception as e:
return False, f"Validation error: {e}"
def list_rules(self):
"""List all rule files"""
rule_files = []
for file in os.listdir(self.rules_directory):
if file.endswith('.yaml') or file.endswith('.yml'):
rule_files.append(file)
return rule_files
def generate_all_rules(self):
"""Generate all default security rules"""
print("Generating Forseti Security rules...")
self.create_firewall_rules()
self.create_iam_rules()
self.create_storage_rules()
self.create_compute_rules()
self.create_cloudsql_rules()
self.create_kubernetes_rules()
self.create_whitelist_rules()
print(f"All rules generated in: {self.rules_directory}")
# List generated rules
rules = self.list_rules()
print(f"Generated {len(rules)} rule files:")
for rule in rules:
print(f" - {rule}")
def main(): """Main function for rule management"""
import argparse
parser = argparse.ArgumentParser(description='Forseti Security Rule Manager')
parser.add_argument('--action', choices=['generate', 'validate', 'list', 'custom'],
required=True, help='Action to perform')
parser.add_argument('--rules-dir', default='/home/forseti/forseti-security/rules',
help='Rules directory path')
parser.add_argument('--rule-file', help='Rule file to validate')
parser.add_argument('--rule-name', help='Custom rule name')
parser.add_argument('--resource-type', help='Resource type for custom rule')
parser.add_argument('--filters', help='Filters for custom rule (JSON format)')
args = parser.parse_args()
manager = ForsetiRuleManager(args.rules_dir)
if args.action == 'generate':
manager.generate_all_rules()
elif args.action == 'validate' and args.rule_file:
valid, message = manager.validate_rule(args.rule_file)
print(f"Validation result: {message}")
exit(0 if valid else 1)
elif args.action == 'list':
rules = manager.list_rules()
print(f"Found {len(rules)} rule files:")
for rule in rules:
print(f" - {rule}")
elif args.action == 'custom':
if not all([args.rule_name, args.resource_type, args.filters]):
print("Custom rule requires: --rule-name, --resource-type, --filters")
exit(1)
try:
filters = json.loads(args.filters)
manager.create_custom_rule(args.rule_name, args.resource_type, filters)
except json.JSONDecodeError:
print("Invalid JSON format for filters")
exit(1)
else:
parser.print_help()
if name == "main": main() ```_
Überwachung und Berichterstattung
Compliance Monitoring
```python
!/usr/bin/env python3
Forseti Security Monitoring and Reporting
import mysql.connector import json import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from datetime import datetime, timedelta import smtplib from email.mime.text import MimeText from email.mime.multipart import MimeMultipart from email.mime.base import MimeBase from email import encoders import logging from google.cloud import storage from google.cloud import securitycenter
class ForsetiMonitor: """Monitor and report on Forseti Security findings"""
def __init__(self, config):
self.config = config
self.setup_logging()
self.setup_connections()
def setup_logging(self):
"""Setup logging configuration"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('forseti_monitor.log'),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
def setup_connections(self):
"""Setup database and GCP connections"""
# MySQL connection
try:
self.db_connection = mysql.connector.connect(
host=self.config['database']['host'],
port=self.config['database']['port'],
database=self.config['database']['database'],
user=self.config['database']['username'],
password=self.config['database']['password']
)
self.logger.info("Database connection established")
except Exception as e:
self.logger.error(f"Failed to connect to database: {e}")
self.db_connection = None
# GCS client
try:
self.storage_client = storage.Client(project=self.config['gcp']['project_id'])
self.logger.info("GCS client initialized")
except Exception as e:
self.logger.error(f"Failed to initialize GCS client: {e}")
self.storage_client = None
# Security Command Center client
try:
self.scc_client = securitycenter.SecurityCenterClient()
self.logger.info("Security Command Center client initialized")
except Exception as e:
self.logger.error(f"Failed to initialize SCC client: {e}")
self.scc_client = None
def get_violations_summary(self, days=30):
"""Get violations summary from database"""
if not self.db_connection:
return None
try:
cursor = self.db_connection.cursor(dictionary=True)
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
# Get violations by rule
cursor.execute("""
SELECT
rule_name,
violation_type,
COUNT(*) as violation_count,
COUNT(DISTINCT resource_id) as affected_resources
FROM violations
WHERE created_at_datetime BETWEEN %s AND %s
GROUP BY rule_name, violation_type
ORDER BY violation_count DESC
""", (start_date, end_date))
violations_by_rule = cursor.fetchall()
# Get violations by resource type
cursor.execute("""
SELECT
resource_type,
COUNT(*) as violation_count,
COUNT(DISTINCT resource_id) as affected_resources
FROM violations
WHERE created_at_datetime BETWEEN %s AND %s
GROUP BY resource_type
ORDER BY violation_count DESC
""", (start_date, end_date))
violations_by_type = cursor.fetchall()
# Get daily trend
cursor.execute("""
SELECT
DATE(created_at_datetime) as violation_date,
COUNT(*) as violation_count
FROM violations
WHERE created_at_datetime BETWEEN %s AND %s
GROUP BY DATE(created_at_datetime)
ORDER BY violation_date
""", (start_date, end_date))
daily_trend = cursor.fetchall()
cursor.close()
summary = {
'period_days': days,
'violations_by_rule': violations_by_rule,
'violations_by_type': violations_by_type,
'daily_trend': daily_trend,
'total_violations': sum(v['violation_count'] for v in violations_by_rule),
'generated_at': datetime.now().isoformat()
}
return summary
except Exception as e:
self.logger.error(f"Error getting violations summary: {e}")
return None
def get_inventory_summary(self):
"""Get inventory summary from database"""
if not self.db_connection:
return None
try:
cursor = self.db_connection.cursor(dictionary=True)
# Get latest inventory
cursor.execute("""
SELECT
inventory_type,
COUNT(*) as resource_count
FROM inventory i
JOIN inventory_index ii ON i.inventory_index_id = ii.inventory_index_id
WHERE ii.id = (SELECT MAX(id) FROM inventory_index WHERE completed_at_datetime IS NOT NULL)
GROUP BY inventory_type
ORDER BY resource_count DESC
""")
inventory_by_type = cursor.fetchall()
# Get inventory history
cursor.execute("""
SELECT
completed_at_datetime,
count_objects
FROM inventory_index
WHERE completed_at_datetime IS NOT NULL
ORDER BY completed_at_datetime DESC
LIMIT 30
""")
inventory_history = cursor.fetchall()
cursor.close()
summary = {
'inventory_by_type': inventory_by_type,
'inventory_history': inventory_history,
'total_resources': sum(i['resource_count'] for i in inventory_by_type),
'generated_at': datetime.now().isoformat()
}
return summary
except Exception as e:
self.logger.error(f"Error getting inventory summary: {e}")
return None
def get_compliance_score(self, violations_summary):
"""Calculate compliance score based on violations"""
if not violations_summary:
return 0
total_violations = violations_summary['total_violations']
# Weight violations by severity (based on rule name patterns)
critical_weight = 10
high_weight = 5
medium_weight = 2
low_weight = 1
weighted_score = 0
for violation in violations_summary['violations_by_rule']:
rule_name = violation['rule_name'].lower()
count = violation['violation_count']
if any(keyword in rule_name for keyword in ['public', 'internet', 'all users', 'owner']):
weighted_score += count * critical_weight
elif any(keyword in rule_name for keyword in ['ssl', 'backup', 'encryption']):
weighted_score += count * high_weight
elif any(keyword in rule_name for keyword in ['logging', 'monitoring']):
weighted_score += count * medium_weight
else:
weighted_score += count * low_weight
# Calculate compliance score (0-100)
max_possible_score = 1000 # Arbitrary baseline
compliance_score = max(0, 100 - (weighted_score / max_possible_score * 100))
return round(compliance_score, 2)
def generate_compliance_report(self, days=30):
"""Generate comprehensive compliance report"""
violations_summary = self.get_violations_summary(days)
inventory_summary = self.get_inventory_summary()
if not violations_summary:
self.logger.error("Failed to generate compliance report")
return None
compliance_score = self.get_compliance_score(violations_summary)
report = {
'report_metadata': {
'generated_at': datetime.now().isoformat(),
'period_days': days,
'report_type': 'forseti_compliance'
},
'executive_summary': {
'compliance_score': compliance_score,
'total_violations': violations_summary['total_violations'],
'total_resources': inventory_summary['total_resources'] if inventory_summary else 0,
'period_days': days
},
'violations_summary': violations_summary,
'inventory_summary': inventory_summary,
'recommendations': self._generate_recommendations(violations_summary)
}
return report
def _generate_recommendations(self, violations_summary):
"""Generate recommendations based on violations"""
recommendations = []
if not violations_summary:
return recommendations
# Analyze top violations
top_violations = sorted(
violations_summary['violations_by_rule'],
key=lambda x: x['violation_count'],
reverse=True
)[:5]
for violation in top_violations:
rule_name = violation['rule_name']
count = violation['violation_count']
if 'public' in rule_name.lower() or 'internet' in rule_name.lower():
recommendations.append({
'priority': 'HIGH',
'title': 'Address Public Access Violations',
'description': f"{count} resources have public access configured",
'action': f"Review and restrict public access for {rule_name}",
'rule_name': rule_name
})
elif 'firewall' in rule_name.lower():
recommendations.append({
'priority': 'HIGH',
'title': 'Review Firewall Rules',
'description': f"{count} firewall rule violations detected",
'action': f"Audit and update firewall rules for {rule_name}",
'rule_name': rule_name
})
elif 'iam' in rule_name.lower() or 'service account' in rule_name.lower():
recommendations.append({
'priority': 'MEDIUM',
'title': 'Review IAM Permissions',
'description': f"{count} IAM-related violations found",
'action': f"Review and update IAM policies for {rule_name}",
'rule_name': rule_name
})
return recommendations
def create_compliance_dashboard(self, report_data, output_file='forseti_dashboard.png'):
"""Create compliance dashboard visualization"""
try:
plt.style.use('seaborn-v0_8')
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
violations_summary = report_data['violations_summary']
inventory_summary = report_data['inventory_summary']
executive_summary = report_data['executive_summary']
# 1. Compliance Score Gauge
compliance_score = executive_summary['compliance_score']
colors = ['#e74c3c' if compliance_score < 70 else '#f39c12' if compliance_score < 85 else '#27ae60']
axes[0, 0].pie([compliance_score, 100-compliance_score],
labels=[f'{compliance_score}%', ''],
colors=[colors[0], '#ecf0f1'],
startangle=90)
axes[0, 0].set_title('Compliance Score')
# 2. Violations by Rule (Top 10)
if violations_summary['violations_by_rule']:
top_rules = violations_summary['violations_by_rule'][:10]
rule_names = [r['rule_name'][:30] + '...' if len(r['rule_name']) > 30 else r['rule_name']
for r in top_rules]
violation_counts = [r['violation_count'] for r in top_rules]
axes[0, 1].barh(rule_names, violation_counts, color='#e74c3c')
axes[0, 1].set_title('Top 10 Violating Rules')
axes[0, 1].set_xlabel('Violation Count')
# 3. Violations by Resource Type
if violations_summary['violations_by_type']:
resource_types = [v['resource_type'] for v in violations_summary['violations_by_type']]
type_counts = [v['violation_count'] for v in violations_summary['violations_by_type']]
axes[0, 2].pie(type_counts, labels=resource_types, autopct='%1.1f%%')
axes[0, 2].set_title('Violations by Resource Type')
# 4. Daily Violation Trend
if violations_summary['daily_trend']:
dates = [datetime.strptime(str(d['violation_date']), '%Y-%m-%d')
for d in violations_summary['daily_trend']]
counts = [d['violation_count'] for d in violations_summary['daily_trend']]
axes[1, 0].plot(dates, counts, marker='o', color='#e74c3c')
axes[1, 0].set_title('Daily Violation Trend')
axes[1, 0].set_ylabel('Violation Count')
axes[1, 0].tick_params(axis='x', rotation=45)
# 5. Inventory by Resource Type
if inventory_summary and inventory_summary['inventory_by_type']:
inv_types = [i['inventory_type'] for i in inventory_summary['inventory_by_type'][:8]]
inv_counts = [i['resource_count'] for i in inventory_summary['inventory_by_type'][:8]]
axes[1, 1].bar(inv_types, inv_counts, color='#3498db')
axes[1, 1].set_title('Inventory by Resource Type')
axes[1, 1].set_ylabel('Resource Count')
axes[1, 1].tick_params(axis='x', rotation=45)
# 6. Summary Metrics
metrics_text = f"""
Total Violations: {executive_summary['total_violations']}
Total Resources: {executive_summary['total_resources']}
Compliance Score: {executive_summary['compliance_score']}%
Period: {executive_summary['period_days']} days
Generated: {report_data['report_metadata']['generated_at'][:10]}
"""
axes[1, 2].text(0.1, 0.5, metrics_text, fontsize=12, verticalalignment='center')
axes[1, 2].set_xlim(0, 1)
axes[1, 2].set_ylim(0, 1)
axes[1, 2].axis('off')
axes[1, 2].set_title('Summary Metrics')
plt.tight_layout()
plt.savefig(output_file, dpi=300, bbox_inches='tight')
plt.close()
self.logger.info(f"Compliance dashboard created: {output_file}")
return output_file
except Exception as e:
self.logger.error(f"Error creating compliance dashboard: {e}")
return None
def send_compliance_report(self, report_data, dashboard_file=None):
"""Send compliance report via email"""
if not self.config.get('notifications', {}).get('email', {}).get('enabled', False):
self.logger.info("Email notifications disabled")
return False
try:
email_config = self.config['notifications']['email']
# Create email message
msg = MimeMultipart()
msg['From'] = email_config['sender']
msg['To'] = email_config['recipient']
msg['Subject'] = f"Forseti Security Compliance Report - {datetime.now().strftime('%Y-%m-%d')}"
# Create email body
executive_summary = report_data['executive_summary']
body = f"""
Forseti Security Compliance Report
Compliance Score: {executive_summary['compliance_score']}%
Total Violations: {executive_summary['total_violations']}
Total Resources: {executive_summary['total_resources']}
Period: {executive_summary['period_days']} days
Top Recommendations:
"""
for rec in report_data['recommendations'][:5]:
body += f"\n- {rec['title']}: {rec['description']}"
body += f"\n\nGenerated at: {report_data['report_metadata']['generated_at']}"
msg.attach(MimeText(body, 'plain'))
# Attach dashboard if available
if dashboard_file:
with open(dashboard_file, 'rb') as attachment:
part = MimeBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
'Content-Disposition',
f'attachment; filename= {dashboard_file}'
)
msg.attach(part)
# Send email
server = smtplib.SMTP(email_config['smtp_host'], email_config['smtp_port'])
server.starttls()
server.login(email_config['username'], email_config['password'])
server.send_message(msg)
server.quit()
self.logger.info("Compliance report sent via email")
return True
except Exception as e:
self.logger.error(f"Error sending compliance report: {e}")
return False
def upload_to_gcs(self, report_data, bucket_name):
"""Upload report to Google Cloud Storage"""
if not self.storage_client:
return False
try:
bucket = self.storage_client.bucket(bucket_name)
# Upload JSON report
report_blob_name = f"forseti-reports/compliance-report-{datetime.now().strftime('%Y%m%d-%H%M%S')}.json"
report_blob = bucket.blob(report_blob_name)
report_blob.upload_from_string(json.dumps(report_data, indent=2))
self.logger.info(f"Report uploaded to GCS: gs://{bucket_name}/{report_blob_name}")
return True
except Exception as e:
self.logger.error(f"Error uploading to GCS: {e}")
return False
def run_monitoring_workflow(self, days=30):
"""Run complete monitoring workflow"""
self.logger.info("Starting Forseti Security monitoring workflow")
# Generate report
report = self.generate_compliance_report(days)
if not report:
self.logger.error("Failed to generate compliance report")
return False
# Save report to file
report_file = f"forseti_compliance_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(report_file, 'w') as f:
json.dump(report, f, indent=2)
# Create dashboard
dashboard_file = f"forseti_dashboard_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
self.create_compliance_dashboard(report, dashboard_file)
# Send report
self.send_compliance_report(report, dashboard_file)
# Upload to GCS
if self.config.get('gcp', {}).get('bucket_name'):
self.upload_to_gcs(report, self.config['gcp']['bucket_name'])
self.logger.info("Forseti Security monitoring workflow completed")
return True
def main(): """Main function for Forseti monitoring"""
import argparse
import yaml
parser = argparse.ArgumentParser(description='Forseti Security Monitor')
parser.add_argument('--config', default='forseti_monitor_config.yaml', help='Configuration file')
parser.add_argument('--days', type=int, default=30, help='Number of days to analyze')
args = parser.parse_args()
# Load configuration
try:
with open(args.config, 'r') as f:
config = yaml.safe_load(f)
except FileNotFoundError:
# Create default configuration
config = {
'database': {
'host': 'localhost',
'port': 3306,
'database': 'forseti_security',
'username': 'forseti_security_user',
'password': 'forseti123'
},
'gcp': {
'project_id': 'your-project-id',
'bucket_name': 'forseti-security-bucket'
},
'notifications': {
'email': {
'enabled': True,
'smtp_host': 'smtp.gmail.com',
'smtp_port': 587,
'username': 'forseti@company.com',
'password': 'app-password',
'sender': 'forseti@company.com',
'recipient': 'security-team@company.com'
}
}
}
with open(args.config, 'w') as f:
yaml.dump(config, f, default_flow_style=False)
print(f"Created default configuration: {args.config}")
print("Please update the configuration file with your settings")
return
# Run monitoring
monitor = ForsetiMonitor(config)
monitor.run_monitoring_workflow(args.days)
if name == "main": main() ```_
Automatisierung und Integration
CI/CD Integration
```yaml
.github/workflows/forseti-security-scan.yml
name: Forseti Security Scan
on: push: branches: [ main, develop ] pull_request: branches: [ main ] schedule: # Run daily at 2 AM UTC - cron: '0 2 * * *' workflow_dispatch: inputs: scan_type: description: 'Type of scan to run' required: false default: 'full' type: choice options: - full - inventory - scanner - explain
jobs: forseti-security-scan: runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: Install dependencies
run: |
pip install google-cloud-storage google-cloud-securitycenter mysql-connector-python pyyaml pandas matplotlib seaborn
- name: Setup Google Cloud credentials
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Setup Google Cloud SDK
uses: google-github-actions/setup-gcloud@v1
- name: Run Forseti Security scan
env:
FORSETI_SERVER_HOST: ${{ secrets.FORSETI_SERVER_HOST }}
FORSETI_SERVER_PORT: ${{ secrets.FORSETI_SERVER_PORT }}
FORSETI_DB_HOST: ${{ secrets.FORSETI_DB_HOST }}
FORSETI_DB_PASSWORD: ${{ secrets.FORSETI_DB_PASSWORD }}
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
GCP_ORGANIZATION_ID: ${{ secrets.GCP_ORGANIZATION_ID }}
run: |
# Create Forseti client configuration
cat > forseti_client_config.yaml << EOF
server_ip: ${FORSETI_SERVER_HOST}
server_port: ${FORSETI_SERVER_PORT}
EOF
# Create monitoring configuration
cat > forseti_monitor_config.yaml << EOF
database:
host: ${FORSETI_DB_HOST}
port: 3306
database: forseti_security
username: forseti_security_user
password: ${FORSETI_DB_PASSWORD}
gcp:
project_id: ${GCP_PROJECT_ID}
organization_id: ${GCP_ORGANIZATION_ID}
bucket_name: forseti-security-bucket
notifications:
email:
enabled: false
EOF
# Install Forseti Security client
git clone https: //github.com/forseti-security/forseti-security.git
cd forseti-security
git checkout v2.25.1
pip install -r requirements.txt
pip install -e .
# Run Forseti operations based on scan type
| SCAN_TYPE="${{ github.event.inputs.scan_type | | 'full' }}" |
| if [ "$SCAN_TYPE" = "full" ] | | [ "$SCAN_TYPE" = "inventory" ]; then | echo "Running inventory scan..." python -m google.cloud.forseti.services.inventory.storage \ --config_file_path=../forseti_client_config.yaml fi
| if [ "$SCAN_TYPE" = "full" ] | | [ "$SCAN_TYPE" = "scanner" ]; then | echo "Running scanner..." python -m google.cloud.forseti.scanner.scanner \ --config_file_path=../forseti_client_config.yaml fi
| if [ "$SCAN_TYPE" = "full" ] | | [ "$SCAN_TYPE" = "explain" ]; then | echo "Running explain..." python -m google.cloud.forseti.services.explain.explain \ --config_file_path=../forseti_client_config.yaml fi
# Generate compliance report
cd ..
python scripts/forseti_monitor.py \
--config forseti_monitor_config.yaml \
--days 7
- name: Evaluate security gate
run: |
python << 'EOF'
import json
import sys
import glob
# Find compliance report
report_files = glob.glob('forseti_compliance_report_*.json')
if not report_files:
print("No compliance report found")
sys.exit(0)
with open(report_files[0], 'r') as f:
report = json.load(f)
executive_summary = report['executive_summary']
compliance_score = executive_summary['compliance_score']
total_violations = executive_summary['total_violations']
print(f"Forseti Security Assessment Results: ")
print(f"Compliance Score: {compliance_score}%")
print(f"Total Violations: {total_violations}")
# Security gate logic
if compliance_score < 70:
print("❌ SECURITY FAILURE!")
print("Compliance score below acceptable threshold (70%)")
sys.exit(1)
if total_violations > 100:
print("⚠️ WARNING: High number of violations!")
sys.exit(1)
print("✅ Security gate passed")
EOF
- name: Upload scan results
uses: actions/upload-artifact@v3
with:
name: forseti-security-results
path: |
forseti_compliance_report_*.json
forseti_dashboard_*.png
- name: Comment PR with security status
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const glob = require('glob');
// Find compliance report
const reportFiles = glob.sync('forseti_compliance_report_*.json');
if (reportFiles.length === 0) {
console.log('No compliance report found');
return;
}
const report = JSON.parse(fs.readFileSync(reportFiles[0], 'utf8'));
const summary = report.executive_summary;
const comment = `## 🔒 Forseti Security Scan Results
**Compliance Score: ** ${summary.compliance_score}%
**Total Violations: ** ${summary.total_violations}
**Total Resources: ** ${summary.total_resources}
**Top Violations: **
${report.violations_summary.violations_by_rule.slice(0, 5).map(v =>
`- ${v.rule_name}: ${v.violation_count} violations`
).join('\n')}
**Recommendations: **
${report.recommendations.slice(0, 3).map(r =>
`- **${r.title}**: ${r.description}`
).join('\n')}
${summary.compliance_score < 70 ? '⚠️ **Compliance score below threshold! Please review and remediate violations.**' : '✅ Security scan passed.'}
[View detailed report](https: //github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
```_
Ressourcen und Dokumentation
Offizielle Mittel
- Forseti Security GitHub Repository - Quellcode und Dokumentation
- Forseti Sicherheitsdokumentation - Offizielle Dokumentation und Anleitungen
- Google Cloud Security - Google Cloud Security Best Practices
- Cloud Security Command Center - Integration mit CSCC
GCP Sicherheitsressourcen
- GCP Security Best Practices - Google Cloud Sicherheitsrichtlinien
- IAM Best Practices - Identitäts- und Zugriffsmanagement
- VPC Security - Virtuelle Private Cloud-Sicherheit
- Cloud Asset Inventory - Asset Discovery and Monitoring
Compliance und Governance
- (CIS) Google Cloud Platform Benchmark](LINK_12) - CIS Benchmarks für GCP
- NIST Cybersecurity Framework - NIST Sicherheitsrahmen
- SOC 2 Compliance - SOC 2 Compliance auf GCP
- DSGVO-Compliance - DSGVO-Compliance-Ressourcen