6.3 Infrastructure Security

6.3 Infrastructure Security #

🎯 Цель изучения #

Научиться обеспечивать безопасность инфраструктуры на всех уровнях: от сетевой безопасности до управления секретами и compliance мониторинга.


🏗️ Infrastructure as Code Security #

Безопасность Terraform #

# ❌ Небезопасная конфигурация
resource "aws_s3_bucket" "example" {
  bucket = "my-bucket"
  
  # Public access!
  acl = "public-read"
}

resource "aws_security_group" "web" {
  # Открыт для всех
  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# Hardcoded secrets
resource "aws_db_instance" "example" {
  password = "hardcoded_password_123"
}
# ✅ Безопасная конфигурация
resource "aws_s3_bucket" "example" {
  bucket = var.bucket_name
}

resource "aws_s3_bucket_acl" "example" {
  bucket = aws_s3_bucket.example.bucket
  acl    = "private"
}

resource "aws_s3_bucket_public_access_block" "example" {
  bucket = aws_s3_bucket.example.bucket

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_security_group" "web" {
  name_prefix = "web-"
  
  # Только HTTPS
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [var.allowed_cidr]
  }
  
  # Explicit egress
  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# Secrets from AWS Secrets Manager
data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = "prod/db/password"
}

resource "aws_db_instance" "example" {
  password = data.aws_secretsmanager_secret_version.db_password.secret_string
  
  # Security best practices
  encrypted               = true
  backup_retention_period = 7
  backup_window          = "03:00-04:00"
  maintenance_window     = "sun:04:00-sun:05:00"
  
  # Network security
  db_subnet_group_name   = aws_db_subnet_group.private.name
  vpc_security_group_ids = [aws_security_group.db.id]
}

🔍 IaC Security Scanning #

Checkov #

# Установка
pip install checkov

# Сканирование Terraform
checkov -d /path/to/terraform --framework terraform

# Сканирование Kubernetes manifests
checkov -d /path/to/k8s --framework kubernetes

# В CI/CD
checkov -d . --framework terraform --output json --quiet > checkov-report.json
# GitHub Actions
- name: Run Checkov action
  uses: bridgecrewio/checkov-action@master
  with:
    directory: .
    quiet: true
    soft_fail: true
    framework: terraform,kubernetes
    output_format: sarif
    output_file_path: reports/results.sarif

Terraform Sentinel (Enterprise) #

# sentinel/require-s3-encryption.sentinel
import "tfplan/v2" as tfplan

# Rule: All S3 buckets must be encrypted
main = rule {
    all tfplan.resource_changes as _, resource_changes {
        resource_changes.type is "aws_s3_bucket" and
        resource_changes.change.after.server_side_encryption_configuration is not null
    }
}

TFSec #

# Установка
go install github.com/aquasecurity/tfsec/cmd/tfsec@latest

# Сканирование
tfsec .

# Исключения
tfsec --exclude AWS002,AWS017 .

# В формате SARIF
tfsec --format sarif . > tfsec-results.sarif

☁️ Cloud Security Posture Management #

AWS Security Best Practices #

IAM Security #

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT:role/DevOpsRole"
      },
      "Action": [
        "ec2:DescribeInstances",
        "ec2:DescribeSecurityGroups"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": ["us-east-1", "us-west-2"]
        },
        "DateGreaterThan": {
          "aws:CurrentTime": "2023-01-01T00:00:00Z"
        }
      }
    }
  ]
}
# Terraform IAM с принципом least privilege
resource "aws_iam_role" "devops_role" {
  name = "DevOpsRole"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
        Condition = {
          StringEquals = {
            "sts:ExternalId" = var.external_id
          }
        }
      }
    ]
  })
}

resource "aws_iam_policy" "devops_policy" {
  name = "DevOpsPolicy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "ec2:DescribeInstances",
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "*"
      }
    ]
  })
}

VPC Security #

# Secure VPC configuration
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name        = "main-vpc"
    Environment = var.environment
  }
}

# Private subnets for databases
resource "aws_subnet" "private" {
  count = length(var.private_subnet_cidrs)

  vpc_id            = aws_vpc.main.id
  cidr_block        = var.private_subnet_cidrs[count.index]
  availability_zone = var.availability_zones[count.index]

  tags = {
    Name = "private-subnet-${count.index + 1}"
    Type = "Private"
  }
}

# Public subnets for load balancers
resource "aws_subnet" "public" {
  count = length(var.public_subnet_cidrs)

  vpc_id                  = aws_vpc.main.id
  cidr_block              = var.public_subnet_cidrs[count.index]
  availability_zone       = var.availability_zones[count.index]
  map_public_ip_on_launch = false  # Explicit public IP assignment

  tags = {
    Name = "public-subnet-${count.index + 1}"
    Type = "Public"
  }
}

# Network ACLs for additional security
resource "aws_network_acl" "private" {
  vpc_id     = aws_vpc.main.id
  subnet_ids = aws_subnet.private[*].id

  # Deny all by default, explicit allow rules
  ingress {
    protocol   = "tcp"
    rule_no    = 100
    action     = "allow"
    cidr_block = aws_vpc.main.cidr_block
    from_port  = 3306
    to_port    = 3306
  }

  egress {
    protocol   = "tcp"
    rule_no    = 100
    action     = "allow"
    cidr_block = aws_vpc.main.cidr_block
    from_port  = 32768
    to_port    = 65535
  }

  tags = {
    Name = "private-nacl"
  }
}

AWS Config Rules #

{
  "ConfigRuleName": "s3-bucket-ssl-requests-only",
  "Description": "Checks whether S3 buckets have policies that require SSL requests",
  "Source": {
    "Owner": "AWS",
    "SourceIdentifier": "S3_BUCKET_SSL_REQUESTS_ONLY"
  },
  "Scope": {
    "ComplianceResourceTypes": [
      "AWS::S3::Bucket"
    ]
  }
}

Azure Security Center #

# Azure Security Center
resource "azurerm_security_center_subscription_pricing" "main" {
  tier          = "Standard"
  resource_type = "VirtualMachines"
}

resource "azurerm_security_center_contact" "main" {
  email               = var.security_contact_email
  phone               = var.security_contact_phone
  alert_notifications = true
  alerts_to_admins    = true
}

🔐 Secrets Management #

HashiCorp Vault #

Установка и настройка #

# Установка Vault
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install vault

# Запуск dev сервера
vault server -dev

# Настройка переменных
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN="dev-token"

Vault конфигурация #

# vault-config.hcl
storage "consul" {
  address = "127.0.0.1:8500"
  path    = "vault/"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = false
  tls_cert_file = "/etc/vault/tls/vault.crt"
  tls_key_file  = "/etc/vault/tls/vault.key"
}

api_addr = "https://vault.example.com:8200"
cluster_addr = "https://vault.example.com:8201"
ui = true

# Audit logging
audit {
  type = "file"
  path = "/var/log/vault/audit.log"
}

Vault Policies #

# Database secrets policy
path "database/creds/readonly" {
  capabilities = ["read"]
}

path "database/creds/readwrite" {
  capabilities = ["read"]
  allowed_parameters = {
    "ttl" = ["1h", "2h", "4h"]
  }
}

# KV secrets policy
path "secret/data/myapp/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}

path "secret/metadata/myapp/*" {
  capabilities = ["list"]
}

AWS Secrets Manager Integration #

# Terraform AWS Secrets Manager
resource "aws_secretsmanager_secret" "db_password" {
  name        = "prod/database/password"
  description = "Database password for production"
  
  rotation_rules {
    automatically_after_days = 30
  }

  tags = {
    Environment = "production"
    Service     = "database"
  }
}

resource "aws_secretsmanager_secret_version" "db_password" {
  secret_id     = aws_secretsmanager_secret.db_password.id
  secret_string = random_password.db_password.result
}

resource "random_password" "db_password" {
  length  = 32
  special = true
}

Kubernetes Secrets Integration #

# External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
  namespace: default
spec:
  provider:
    vault:
      server: "https://vault.example.com:8200"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "myapp-role"
          serviceAccountRef:
            name: external-secrets-sa

---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secrets
  namespace: default
spec:
  refreshInterval: 30s
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: app-secrets
    creationPolicy: Owner
  data:
  - secretKey: database-url
    remoteRef:
      key: secret/myapp
      property: database_url
  - secretKey: api-key
    remoteRef:
      key: secret/myapp
      property: api_key

🌐 Network Security #

Micro-segmentation #

Kubernetes Network Policies #

# Default deny all policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

---
# Allow specific communication
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-netpol
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432
  - to: []  # Allow DNS
    ports:
    - protocol: UDP
      port: 53

Istio Security Policies #

# Istio AuthorizationPolicy
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: web-authz
  namespace: production
spec:
  selector:
    matchLabels:
      app: web
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/frontend"]
    to:
    - operation:
        methods: ["GET", "POST"]
        paths: ["/api/*"]
    when:
    - key: request.headers[user-role]
      values: ["admin", "user"]

---
# Istio PeerAuthentication (mTLS)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT

Web Application Firewall (WAF) #

# AWS WAF
resource "aws_wafv2_web_acl" "main" {
  name  = "main-waf"
  scope = "CLOUDFRONT"

  default_action {
    allow {}
  }

  # Rate limiting
  rule {
    name     = "rate-limit"
    priority = 1

    action {
      block {}
    }

    statement {
      rate_based_statement {
        limit              = 2000
        aggregate_key_type = "IP"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "rate-limit-rule"
      sampled_requests_enabled   = true
    }
  }

  # OWASP Top 10
  rule {
    name     = "owasp-top-10"
    priority = 2

    action {
      block {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesOWASPTop10RuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "owasp-top-10-rule"
      sampled_requests_enabled   = true
    }
  }
}

🛡️ Runtime Security #

Falco для Kubernetes #

# Falco DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: falco
  namespace: falco-system
spec:
  selector:
    matchLabels:
      app: falco
  template:
    metadata:
      labels:
        app: falco
    spec:
      serviceAccountName: falco
      hostNetwork: true
      hostPID: true
      containers:
      - name: falco
        image: falcosecurity/falco:0.35.1
        securityContext:
          privileged: true
        env:
        - name: FALCO_K8S_AUDIT_ENDPOINT
          value: "http://localhost:8765/k8s-audit"
        volumeMounts:
        - mountPath: /host/var/run/docker.sock
          name: docker-socket
        - mountPath: /host/proc
          name: proc-fs
        - mountPath: /host/boot
          name: boot-fs
        - mountPath: /etc/falco
          name: falco-config
      volumes:
      - name: docker-socket
        hostPath:
          path: /var/run/docker.sock
      - name: proc-fs
        hostPath:
          path: /proc
      - name: boot-fs
        hostPath:
          path: /boot
      - name: falco-config
        configMap:
          name: falco-config
# Custom Falco Rules
apiVersion: v1
kind: ConfigMap
metadata:
  name: falco-config
  namespace: falco-system
data:
  custom_rules.yaml: |
    - rule: Suspicious Network Activity
      desc: Detect suspicious network connections
      condition: >
        spawned_process and container and
        proc.name in (nc, ncat, netcat, wget, curl) and
        proc.args contains "http://"
      output: >
        Suspicious network activity detected
        (user=%user.name container=%container.name 
         image=%container.image.repository command=%proc.cmdline)
      priority: WARNING
      
    - rule: Privilege Escalation Attempt
      desc: Detect attempts to escalate privileges
      condition: >
        spawned_process and container and
        (proc.name in (sudo, su) or
         proc.args contains "chmod +s")
      output: >
        Privilege escalation attempt
        (user=%user.name container=%container.name command=%proc.cmdline)
      priority: CRITICAL

📊 Compliance Monitoring #

CIS Benchmarks #

# Kube-bench для CIS Kubernetes Benchmark
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml

# Результат
kubectl logs job/kube-bench
# Custom kube-bench job
apiVersion: batch/v1
kind: Job
metadata:
  name: kube-bench
spec:
  template:
    metadata:
      labels:
        app: kube-bench
    spec:
      hostPID: true
      containers:
      - name: kube-bench
        image: aquasec/kube-bench:latest
        command: ["kube-bench"]
        args: ["--version", "1.23"]
        volumeMounts:
        - name: var-lib-etcd
          mountPath: /var/lib/etcd
          readOnly: true
        - name: var-lib-kubelet
          mountPath: /var/lib/kubelet
          readOnly: true
        - name: etc-kubernetes
          mountPath: /etc/kubernetes
          readOnly: true
      restartPolicy: Never
      volumes:
      - name: var-lib-etcd
        hostPath:
          path: "/var/lib/etcd"
      - name: var-lib-kubelet
        hostPath:
          path: "/var/lib/kubelet"
      - name: etc-kubernetes
        hostPath:
          path: "/etc/kubernetes"

Open Policy Agent (OPA) Gatekeeper #

# Constraint Template - Required Labels
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        type: object
        properties:
          labels:
            type: array
            items:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        
        violation[{"msg": msg}] {
          required := input.parameters.labels
          provided := input.review.object.metadata.labels
          missing := required[_]
          not provided[missing]
          msg := sprintf("Missing required label: %v", [missing])
        }

---
# Constraint Instance
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: must-have-environment-label
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
  parameters:
    labels: ["environment", "team", "app"]

🎯 Практические задания #

🟢 Задание 1: IaC Security Scanning #

# 1. Создать уязвимую Terraform конфигурацию
cat > main.tf << 'EOF'
resource "aws_s3_bucket" "example" {
  bucket = "my-public-bucket"
  acl    = "public-read"
}

resource "aws_security_group" "web" {
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
EOF

# 2. Сканирование с Checkov
pip install checkov
checkov -f main.tf

# 3. Исправить проблемы
cat > main.tf << 'EOF'
resource "aws_s3_bucket" "example" {
  bucket = "my-private-bucket"
}

resource "aws_s3_bucket_acl" "example" {
  bucket = aws_s3_bucket.example.bucket
  acl    = "private"
}

resource "aws_security_group" "web" {
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/8"]
  }
}
EOF

🟡 Задание 2: Secrets Management #

# 1. Запустить Vault dev server
vault server -dev &
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN="dev-token"

# 2. Создать секреты
vault kv put secret/myapp \
  database_password="super_secure_password" \
  api_key="secret_api_key_123"

# 3. Создать policy
vault policy write myapp-policy - << 'EOF'
path "secret/data/myapp" {
  capabilities = ["read"]
}
EOF

# 4. Создать token с policy
vault token create -policy=myapp-policy

🟠 Задание 3: Network Policies #

# 1. Создать test namespace
kubectl create namespace test-security

# 2. Применить default deny policy
cat << 'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: test-security
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF

# 3. Создать test pods
kubectl run web --image=nginx -n test-security --labels="app=web"
kubectl run client --image=busybox -n test-security --labels="app=client" -- sleep 3600

# 4. Проверить connectivity (должен быть заблокирован)
kubectl exec -n test-security client -- wget -qO- --timeout=2 web

# 5. Создать allow policy
cat << 'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-client-to-web
  namespace: test-security
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: client
    ports:
    - protocol: TCP
      port: 80
EOF

# 6. Проверить connectivity (должен работать)
kubectl exec -n test-security client -- wget -qO- --timeout=2 web

📚 Полезные ресурсы #

🛠️ Инструменты #

  • IaC Security: Checkov, TFSec, Terrascan, Terraform Sentinel
  • Secrets Management: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault
  • Runtime Security: Falco, Twistlock, Aqua Security, Sysdig
  • Compliance: Kube-bench, Docker Bench, CIS-CAT

📖 Стандарты и Frameworks #


🎯 Результаты изучения #

После изучения этого раздела вы:

  • ✅ Умеете обеспечивать безопасность Infrastructure as Code
  • ✅ Знаете как настроить cloud security posture management
  • ✅ Можете управлять секретами с помощью Vault и cloud providers
  • ✅ Понимаете принципы network security и micro-segmentation
  • ✅ Умеете настраивать runtime security мониторинг

Следующий раздел: 6.4 Container и Kubernetes Security