diff --git a/.github/workflows/IaC_Sec_checks.yml b/.github/workflows/IaC_Sec_checks.yml
index 864a734..3dd772f 100644
--- a/.github/workflows/IaC_Sec_checks.yml
+++ b/.github/workflows/IaC_Sec_checks.yml
@@ -4,13 +4,9 @@ permissions: read-all
on:
pull_request:
- types: [opened, reopened]
+ types: [opened, reopened, synchronize, edited]
+
- push:
- branches:
- - 'final-assessment'
- paths:
- - 'src/final-assessment/**'
@@ -27,19 +23,22 @@ jobs:
steps:
- uses: actions/checkout@v3
+
- name: Check if pull request is opened/reopened
id: pr_status
uses: octokit/request-action@v2.x
with:
- route: GET /repos/RunCor399/Terraform-IaCSec/pulls/${{ github.event.pull_request.number }}
+ route: GET /repos/RunCor399/Terraform-IaCSec/pulls/${{ github.event.number }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Checkov GitHub Action
uses: bridgecrewio/checkov-action@v12
- if: ${{ steps.pr_status.outputs.data.state == 'open' || steps.pr_status.outputs.data.state == 'reopened' }}
+ #if: ${{ steps.pr_status.outputs.data.state == 'open' || steps.pr_status.outputs.data.state == 'reopened' }}
+
with:
+ #check: 'LOW,MEDIUM,HIGH,CRITICAL'
output_format: cli,sarif
output_file_path: console,results.sarif
@@ -49,5 +48,5 @@ jobs:
if: success() || failure()
with:
sarif_file: results.sarif
- ref: ${{ github.head_ref }}
- sha: ${{ github.sha }}
+ ref: "refs/pull/${{ github.event.pull_request.number }}/merge"
+ sha: ${{ github.event.pull_request.head.sha }}
diff --git a/.gitignore b/.gitignore
index 972e0fc..a349cd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,6 @@ override.tf.json
*.env
**/secrets.tf
+**IaCSec/iacsec-assessment.md
+
+
diff --git a/src/final-assessment/IaCSec/Azure_Observability/.terraform.lock.hcl b/src/final-assessment/IaCSec/Azure_Observability/.terraform.lock.hcl
new file mode 100644
index 0000000..73a61eb
--- /dev/null
+++ b/src/final-assessment/IaCSec/Azure_Observability/.terraform.lock.hcl
@@ -0,0 +1,41 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/azuread" {
+ version = "2.15.0"
+ constraints = "~> 2.15.0"
+ hashes = [
+ "h1:9VXImUw/N5trbHEQiE2jaRidbN0uMx7K1xNwA4J5rfk=",
+ "zh:2fde02166f973f14c176aac01346bcce5aaa6fac34e47c83ab5a5bb2da4e554a",
+ "zh:39f955acc2ae67c2f939cc949e9026b3f2ff04da1ef6f12a080f588a356de2d9",
+ "zh:40efd3c358046788940560049a22588fb280e4720f77a861148d39e1855f357c",
+ "zh:6a51776492efb85e5a792e082bceb2fc953ffca8e3c7b9f18b0702dc3b64b704",
+ "zh:78fc976f020e7859141476fd930b48bc5701c0572db15dda38deb00f6f7698f0",
+ "zh:79528395629153a84d45a14ecc525115ad17e7d9caab8d4561a5060658aeb8ee",
+ "zh:cad982edfed3602eb85f3fd39a7783b210fa2786d53e14a0d454c0c2adc57d84",
+ "zh:e39b7de43f5933e0e9d7eaeb89b5a015880dfe51697cd985ae31198cf08a5c75",
+ "zh:ecd856ae46e22518c08c5db862844a8ed9052599c099e950e92b02352495c2c9",
+ "zh:f8a5f15fc6f9d0b1eaeb9bdae2e506e1fc16f18103a314b0acbb3fb62bf86345",
+ "zh:f984c2024599881e68d234e93951c3a54e849e28e15591f5659e83e480c41beb",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.52.0"
+ constraints = "3.52.0"
+ hashes = [
+ "h1:atlTwMcGXXF0rKzLNZhKj7djwoKT4b6in+xa2Hz09Y8=",
+ "zh:0c3029da7454f2fe7058939d95c458d9930842f06430cfcd0713713f3d788216",
+ "zh:826584f11eaaec7f179e85d9cc4833ec7a1d854ed4883c94317427ddfa7ffd11",
+ "zh:8fff204176ee1b08d168848d4bd7a051d7fd189688ca8b5f26eb31855ea060a6",
+ "zh:a170ebe199b93ea1f20357d848dfd0f5e50538236f09939d1a11a61dfbfded0f",
+ "zh:acea54d715186101f8a7725997578b231e4db50eea0fb9f9868ecd867008e6e6",
+ "zh:ae0f6a61677282a2f605ca9d0a74a08ae78ae2efeb372a33b9d4c7210fbbfd2c",
+ "zh:c2c2329f3864e10ee15993c1a48e79bf72d570bb6d08003038a37b73e551dbf9",
+ "zh:c7a4a117628ff0ad24e9c73f1087e9a02b8eca633b0913ee1687b0b4b5c7f377",
+ "zh:e1a290e708e7dbbde8747a98680f7a1aace97694a243ba7a11cc5c77e982e9cc",
+ "zh:e82aa1c5e8ead3087968d7f44b6f644ef3092a0d243b4b575ff8847616e290b3",
+ "zh:f4d57d3c5f3c7fe064b88151036037b7852be6bcfa661e3f4fe0fda2871006d9",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
diff --git a/src/final-assessment/IaCSec/Azure_Observability/aks.tf b/src/final-assessment/IaCSec/Azure_Observability/aks.tf
new file mode 100644
index 0000000..656f728
--- /dev/null
+++ b/src/final-assessment/IaCSec/Azure_Observability/aks.tf
@@ -0,0 +1,53 @@
+
+
+resource "azurerm_kubernetes_cluster" "aks_cluster" {
+ name = "aks-cluster"
+ location = var.observability_rg.location
+ resource_group_name = var.observability_rg.name
+ sku_tier = "Free"
+ local_account_disabled = true
+ api_server_authorized_ip_ranges = "0.0.0.0/0"
+ private_cluster_enabled = true
+
+ default_node_pool {
+ name = "default"
+ node_count = 1
+ vm_size = "standard_d2_v2"
+ max_pods = 51
+ }
+
+// Add role assignment for azure user
+ identity {
+ type = "SystemAssigned"
+ }
+
+ # Uses Azure AD to authenticate users to K8s, refer to: https://learn.microsoft.com/en-us/azure/aks/azure-ad-rbac?tabs=portal
+ # azure_active_directory_role_based_access_control {
+ # managed = true
+ # // it should be a group id, i've used my own object id
+ # admin_group_object_ids = ["9bd70693-8b50-432a-8876-a8096e9fb4b6"]
+ # azure_rbac_enabled = true
+ # }
+
+ network_profile {
+ network_plugin = "azure"
+ }
+
+ http_application_routing_enabled = true
+
+ oms_agent {
+ log_analytics_workspace_id = azurerm_log_analytics_workspace.log_analytics_workspace.id
+ }
+
+ linux_profile {
+ admin_username = "adminuser"
+ ssh_key {
+ key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCuE9WgQR2C4zPDRLDoMiSgqbsdXjgPFT5YkJFAmnyBO9oIoosAe/s2MBZkasz3IcW3/yrH8r8y4c7UTkAu1dzv+CJNS7Axcg2PNXUdTdZCZp0WHgeLMtlzLHWZRFltVP9wHuM3n206IyJ2iSm3sY8ZfViHWoo6bjHb0cOYL/+vEk7Chvces0gUwHTSTKFuX68x1iWRKTgxqQRSS7yz3wZqB+OxAVLvt7fHGV6nWDGVHsErXXFU7QKUvZQ//cKu1U/dMED3JWKWJEthHqCFOgPQ4PWc0kRe5l6CF+NrzfPKJT8cN9XcNj6kOUu2dMMQx3px6Mr5VjV/0xNQmmoZm0M2YCaq3mbpQEM7fO4xCKJRAlKai/q12N0/DCC4t1CxUhqhyvwiL/O1drOqhFEmsB7Yg+/FiynFjZqvt78RE3gP7t7xmBVRckDSRWTbTQqaLMNryuu6+gEXamOF0pPNCpmSPizCRd1t3D/x13IFHjVqzF9QbGRg0dYcV55izrHvatxRcggfEdBH1DTtuwWV3LftueNeXplRRUcq2MTF1SJQkHhnPzezLwQr9pGVKSFT2QjS5q67MAfK7gC7tSqoT6SVhRd4LFtH2spubLqZnLAN/OBK/atbJn3LVTxKFDd23eDTrwH7R20FUkyNmDYvDvRudlZDGQFs76msZtvcKZgb2Q== runcor3@LAPTOP-36GVQ98F"
+ }
+ }
+
+ dns_prefix = "observability-aks"
+
+ depends_on = [azurerm_log_analytics_workspace.log_analytics_workspace,
+ azurerm_resource_group.observability_rg]
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/Azure_Observability/grafana.tf b/src/final-assessment/IaCSec/Azure_Observability/grafana.tf
new file mode 100644
index 0000000..6362547
--- /dev/null
+++ b/src/final-assessment/IaCSec/Azure_Observability/grafana.tf
@@ -0,0 +1,46 @@
+data "azurerm_subscription" "primary" {}
+
+
+resource "azurerm_dashboard_grafana" "grafana-dashboard" {
+ name = var.grafana-dashboard.name
+ resource_group_name = var.observability_rg.name
+ location = var.grafana-dashboard.location
+
+ auto_generated_domain_name_label_scope = "TenantReuse"
+ public_network_access_enabled = true
+ api_key_enabled = false
+ deterministic_outbound_ip_enabled = false
+ zone_redundancy_enabled = false
+
+ sku = "Standard"
+
+ identity {
+ type = "SystemAssigned"
+ }
+
+ depends_on = [azurerm_resource_group.observability_rg]
+}
+
+
+// Works, evaluate how to remove hardcoded principal id (probably the commented line is enough)
+resource "azurerm_role_assignment" "grafana-reader-role-assignment" {
+ #name = "monitoring-reader-role-assignment"
+ scope = data.azurerm_subscription.primary.id
+ principal_id = azurerm_dashboard_grafana.grafana-dashboard.identity[0].principal_id
+ #principal_id = "84edb984-ec6d-46ab-b236-83d3185ee2ad"
+ role_definition_name = "Monitoring Reader"
+}
+
+
+data "azuread_user" "ad_user" {
+ #user_principal_name = "s297014@studenti.polito.it"
+ user_principal_name = "ma.colotti_reply.it#EXT#@francescoborgognihotmailit.onmicrosoft.com"
+}
+
+// "Grafana Admin" role should work, principal Id should be my own account
+resource "azurerm_role_assignment" "grafana-admin-role-assignment" {
+ # name = "monitoring-admin-role-assignment"
+ scope = azurerm_dashboard_grafana.grafana-dashboard.id
+ principal_id = data.azuread_user.ad_user.id
+ role_definition_name = "Grafana Admin"
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/Azure_Observability/log_analytics.tf b/src/final-assessment/IaCSec/Azure_Observability/log_analytics.tf
new file mode 100644
index 0000000..8328ede
--- /dev/null
+++ b/src/final-assessment/IaCSec/Azure_Observability/log_analytics.tf
@@ -0,0 +1,9 @@
+
+resource "azurerm_log_analytics_workspace" "log_analytics_workspace" {
+ name = var.log-analytics-workspace.name
+ location = var.log-analytics-workspace.location
+ resource_group_name = var.observability_rg.name
+ sku = "PerGB2018"
+
+ depends_on = [azurerm_resource_group.observability_rg]
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/Azure_Observability/main.tf b/src/final-assessment/IaCSec/Azure_Observability/main.tf
new file mode 100644
index 0000000..13e7942
--- /dev/null
+++ b/src/final-assessment/IaCSec/Azure_Observability/main.tf
@@ -0,0 +1,38 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "3.52.0"
+ }
+
+ azuread = {
+ source = "hashicorp/azuread"
+ version = "~> 2.15.0"
+ }
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform-rg"
+ storage_account_name = "terraformbackendmanuel"
+ container_name = "tfstate"
+ key = "terraform.tfstate_observability"
+ }
+}
+
+
+provider "azurerm" {
+ subscription_id = var.credentials["subscription_id"]
+ client_id = var.credentials["client_id"]
+ client_secret = var.azure_sp_key
+ tenant_id = var.credentials["tenant_id"]
+ features {
+ resource_group {
+ prevent_deletion_if_contains_resources = false
+ }
+ }
+}
+
+resource "azurerm_resource_group" "observability_rg" {
+ name = var.observability_rg.name
+ location = var.observability_rg.location
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/Azure_Observability/variables.tf b/src/final-assessment/IaCSec/Azure_Observability/variables.tf
new file mode 100644
index 0000000..53b5077
--- /dev/null
+++ b/src/final-assessment/IaCSec/Azure_Observability/variables.tf
@@ -0,0 +1,37 @@
+variable "azure_sp_key" {}
+
+variable "credentials" {
+ description = "Azure Service Provider Credentials"
+ type = map(string)
+ default = {
+ subscription_id = "945fc713-dc5d-4ba6-9b6b-2f1fb2225b19"
+ tenant_id = "c5179d57-9fa0-4d70-bf82-c3e49fc377d9"
+ client_id = "8267d52d-29b9-4a06-ac44-1c6743c8b010"
+ }
+}
+
+
+variable "observability_rg" {
+ description = "Observavility Resource Group"
+ type = map(string)
+ default = {
+ name = "observability_rg"
+ location = "westeurope"
+ }
+}
+
+variable "log-analytics-workspace" {
+ type = map(string)
+ default = {
+ name = "log-analytics-workspace"
+ location = "westeurope"
+ }
+}
+
+variable "grafana-dashboard" {
+ type = map(string)
+ default = {
+ name = "grafana-dashboard"
+ location = "westeurope"
+ }
+}
diff --git a/src/final-assessment/IaCSec/Kubernetes/db_connector_manifest.yml b/src/final-assessment/IaCSec/Kubernetes/db_connector_manifest.yml
new file mode 100644
index 0000000..17aa6e5
--- /dev/null
+++ b/src/final-assessment/IaCSec/Kubernetes/db_connector_manifest.yml
@@ -0,0 +1,82 @@
+# Load Balancer Service
+apiVersion: v1
+kind: Service
+metadata:
+ name: db-external
+spec:
+ type: LoadBalancer
+ selector:
+ app: db-connector
+ ports:
+ - name: db-connector
+ port: 8888
+ targetPort: 8888
+---
+# Internal Service
+apiVersion: v1
+kind: Service
+metadata:
+ name: db-connector
+spec:
+ type: ClusterIP
+ selector:
+ app: db-connector
+ ports:
+ - name: custom-port
+ port: 8888
+ targetPort: 8888
+---
+# Spring App Deployment
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: db-connector
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: db-connector
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: db-connector
+ spec:
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ containers:
+ - name: db-connector
+ #checkov:skip=CKV_K8S_43:No image digest
+ #checkov:skip=CKV_K8S_14:No image tag
+ image: runcor3/db_connector:latest
+ securityContext:
+ readOnlyRootFilesystem: true
+ allowPrivilegeEscalation: false
+ runAsUser: 20000
+ runAsGroup: {{.Value}}
+ capabilities:
+ drop:
+ - ALL
+ livenessProbe:
+ exec:
+ command:
+ - cat
+ - /tmp/healthy
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: 8080
+ initialDelaySeconds: 15
+ timeoutSeconds: 1
+ ports:
+ - containerPort: 8888
+ lifecycle:
+ postStart:
+ exec:
+ command: ["/bin/sh", "-c"]
+ args: ["export KUBE_TOKEN=/var/run/secrets/kubernetes.io/serviceaccount/token"]
+
+
diff --git a/src/final-assessment/IaCSec/Kubernetes/kubernetes_manifest_edited.yml b/src/final-assessment/IaCSec/Kubernetes/kubernetes_manifest_edited.yml
new file mode 100644
index 0000000..4180e2d
--- /dev/null
+++ b/src/final-assessment/IaCSec/Kubernetes/kubernetes_manifest_edited.yml
@@ -0,0 +1,904 @@
+# Copyright 2018 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ----------------------------------------------------------
+# WARNING: This file is autogenerated. Do not manually edit.
+# ----------------------------------------------------------
+
+# [START gke_release_kubernetes_manifests_microservices_demo]
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: emailservice
+spec:
+ selector:
+ matchLabels:
+ app: emailservice
+ template:
+ metadata:
+ labels:
+ app: emailservice
+ role: mail-service
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/emailservice:v0.6.0
+ ports:
+ - containerPort: 8080
+ env:
+ - name: PORT
+ value: "8080"
+ - name: DISABLE_PROFILER
+ value: "1"
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ livenessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: emailservice
+spec:
+ type: ClusterIP
+ selector:
+ app: emailservice
+ ports:
+ - name: grpc
+ port: 5000
+ targetPort: 8080
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: checkoutservice
+spec:
+ selector:
+ matchLabels:
+ app: checkoutservice
+ template:
+ metadata:
+ labels:
+ app: checkoutservice
+ spec:
+ serviceAccountName: default
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/checkoutservice:v0.6.0
+ ports:
+ - containerPort: 5050
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:5050"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:5050"]
+ env:
+ - name: PORT
+ value: "5050"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: SHIPPING_SERVICE_ADDR
+ value: "shippingservice:50051"
+ - name: PAYMENT_SERVICE_ADDR
+ value: "paymentservice:50051"
+ - name: EMAIL_SERVICE_ADDR
+ value: "emailservice:5000"
+ - name: CURRENCY_SERVICE_ADDR
+ value: "currencyservice:7000"
+ - name: CART_SERVICE_ADDR
+ value: "cartservice:7070"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: checkoutservice
+spec:
+ type: ClusterIP
+ selector:
+ app: checkoutservice
+ ports:
+ - name: grpc
+ port: 5050
+ targetPort: 5050
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: recommendationservice
+spec:
+ selector:
+ matchLabels:
+ app: recommendationservice
+ template:
+ metadata:
+ labels:
+ app: recommendationservice
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/recommendationservice:v0.6.0
+ ports:
+ - containerPort: 8080
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ livenessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:8080"]
+ env:
+ - name: PORT
+ value: "8080"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: DISABLE_PROFILER
+ value: "1"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 220Mi
+ limits:
+ cpu: 200m
+ memory: 450Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: recommendationservice
+spec:
+ type: ClusterIP
+ selector:
+ app: recommendationservice
+ ports:
+ - name: grpc
+ port: 8080
+ targetPort: 8080
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: frontend
+spec:
+ selector:
+ matchLabels:
+ app: frontend
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: frontend
+ annotations:
+ sidecar.istio.io/rewriteAppHTTPProbers: "true"
+ spec:
+ serviceAccountName: default
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/frontend:v0.6.0
+ ports:
+ - containerPort: 8080
+ readinessProbe:
+ initialDelaySeconds: 10
+ httpGet:
+ path: "/_healthz"
+ port: 8080
+ httpHeaders:
+ - name: "Cookie"
+ value: "shop_session-id=x-readiness-probe"
+ livenessProbe:
+ initialDelaySeconds: 10
+ httpGet:
+ path: "/_healthz"
+ port: 8080
+ httpHeaders:
+ - name: "Cookie"
+ value: "shop_session-id=x-liveness-probe"
+ env:
+ - name: PORT
+ value: "8080"
+ - name: PRODUCT_CATALOG_SERVICE_ADDR
+ value: "productcatalogservice:3550"
+ - name: CURRENCY_SERVICE_ADDR
+ value: "currencyservice:7000"
+ - name: CART_SERVICE_ADDR
+ value: "cartservice:7070"
+ - name: RECOMMENDATION_SERVICE_ADDR
+ value: "recommendationservice:8080"
+ - name: SHIPPING_SERVICE_ADDR
+ value: "shippingservice:50051"
+ - name: CHECKOUT_SERVICE_ADDR
+ value: "checkoutservice:5050"
+ - name: AD_SERVICE_ADDR
+ value: "adservice:9555"
+ # # ENV_PLATFORM: One of: local, gcp, aws, azure, onprem, alibaba
+ # # When not set, defaults to "local" unless running in GKE, otherwies auto-sets to gcp
+ - name: ENV_PLATFORM
+ value: "azure"
+ - name: ENABLE_PROFILER
+ value: "0"
+ # - name: CYMBAL_BRANDING
+ # value: "true"
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: frontend
+spec:
+ type: ClusterIP
+ selector:
+ app: frontend
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: frontend-external
+spec:
+ type: LoadBalancer
+ selector:
+ app: frontend
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: paymentservice
+spec:
+ selector:
+ matchLabels:
+ app: paymentservice
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: paymentservice
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/paymentservice:v0.6.0
+ ports:
+ - containerPort: 50051
+ env:
+ - name: PORT
+ value: "50051"
+ - name: DISABLE_PROFILER
+ value: "1"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: paymentservice
+spec:
+ type: ClusterIP
+ selector:
+ app: paymentservice
+ ports:
+ - name: grpc
+ port: 50051
+ targetPort: 50051
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: productcatalogservice
+spec:
+ selector:
+ matchLabels:
+ app: productcatalogservice
+ template:
+ metadata:
+ labels:
+ app: productcatalogservice
+ role: default-deployment
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.6.0
+ ports:
+ - containerPort: 3550
+ env:
+ - name: PORT
+ value: "3550"
+ - name: DISABLE_PROFILER
+ value: "1"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:3550"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:3550"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: productcatalogservice
+spec:
+ type: ClusterIP
+ selector:
+ app: productcatalogservice
+ ports:
+ - name: grpc
+ port: 3550
+ targetPort: 3550
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: cartservice
+spec:
+ selector:
+ matchLabels:
+ app: cartservice
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: cartservice
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/cartservice:v0.6.0
+ ports:
+ - containerPort: 7070
+ env:
+ - name: REDIS_ADDR
+ value: "redis-cart:6379"
+ resources:
+ requests:
+ cpu: 200m
+ memory: 64Mi
+ limits:
+ cpu: 300m
+ memory: 128Mi
+ readinessProbe:
+ initialDelaySeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
+ livenessProbe:
+ initialDelaySeconds: 15
+ periodSeconds: 10
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"]
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: cartservice
+spec:
+ type: ClusterIP
+ selector:
+ app: cartservice
+ ports:
+ - name: grpc
+ port: 7070
+ targetPort: 7070
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: loadgenerator
+spec:
+ selector:
+ matchLabels:
+ app: loadgenerator
+ role: default-deployment
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: loadgenerator
+ annotations:
+ sidecar.istio.io/rewriteAppHTTPProbers: "true"
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ restartPolicy: Always
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ initContainers:
+ - command:
+ - /bin/sh
+ - -exc
+ - |
+ echo "Init container pinging frontend: ${FRONTEND_ADDR}..."
+ STATUSCODE=$(wget --server-response http://${FRONTEND_ADDR} 2>&1 | awk '/^ HTTP/{print $2}')
+ if test $STATUSCODE -ne 200; then
+ echo "Error: Could not reach frontend - Status code: ${STATUSCODE}"
+ exit 1
+ fi
+ name: frontend-check
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: busybox:latest
+ env:
+ - name: FRONTEND_ADDR
+ value: "frontend:80"
+ containers:
+ - name: main
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/loadgenerator:v0.6.0
+ env:
+ - name: FRONTEND_ADDR
+ value: "frontend:80"
+ - name: USERS
+ value: "10"
+ resources:
+ requests:
+ cpu: 300m
+ memory: 256Mi
+ limits:
+ cpu: 500m
+ memory: 512Mi
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: currencyservice
+spec:
+ selector:
+ matchLabels:
+ app: currencyservice
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: currencyservice
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/currencyservice:v0.6.0
+ ports:
+ - name: grpc
+ containerPort: 7000
+ env:
+ - name: PORT
+ value: "7000"
+ - name: DISABLE_PROFILER
+ value: "1"
+ readinessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7000"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:7000"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: currencyservice
+spec:
+ type: ClusterIP
+ selector:
+ app: currencyservice
+ ports:
+ - name: grpc
+ port: 7000
+ targetPort: 7000
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: shippingservice
+spec:
+ selector:
+ matchLabels:
+ app: shippingservice
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: shippingservice
+ spec:
+ serviceAccountName: default
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/shippingservice:v0.6.0
+ ports:
+ - containerPort: 50051
+ env:
+ - name: PORT
+ value: "50051"
+ - name: DISABLE_PROFILER
+ value: "1"
+ readinessProbe:
+ periodSeconds: 5
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ livenessProbe:
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:50051"]
+ resources:
+ requests:
+ cpu: 100m
+ memory: 64Mi
+ limits:
+ cpu: 200m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: shippingservice
+spec:
+ type: ClusterIP
+ selector:
+ app: shippingservice
+ ports:
+ - name: grpc
+ port: 50051
+ targetPort: 50051
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis-cart
+spec:
+ selector:
+ matchLabels:
+ app: redis-cart
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: redis-cart
+ spec:
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: redis
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: redis:alpine
+ ports:
+ - containerPort: 6379
+ readinessProbe:
+ periodSeconds: 5
+ tcpSocket:
+ port: 6379
+ livenessProbe:
+ periodSeconds: 5
+ tcpSocket:
+ port: 6379
+ volumeMounts:
+ - mountPath: /data
+ name: redis-data
+ resources:
+ limits:
+ memory: 256Mi
+ cpu: 125m
+ requests:
+ cpu: 70m
+ memory: 200Mi
+ volumes:
+ - name: redis-data
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis-cart
+spec:
+ type: ClusterIP
+ selector:
+ app: redis-cart
+ ports:
+ - name: tcp-redis
+ port: 6379
+ targetPort: 6379
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: adservice
+spec:
+ selector:
+ matchLabels:
+ app: adservice
+ role: default-deployment
+ template:
+ metadata:
+ labels:
+ app: adservice
+ spec:
+ serviceAccountName: default
+ terminationGracePeriodSeconds: 5
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsNonRoot: true
+ runAsUser: 20000
+ containers:
+ - name: server
+ imagePullPolicy: Always
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ image: gcr.io/google-samples/microservices-demo/adservice:v0.6.0
+ ports:
+ - containerPort: 9555
+ env:
+ - name: PORT
+ value: "9555"
+ resources:
+ requests:
+ cpu: 200m
+ memory: 180Mi
+ limits:
+ cpu: 300m
+ memory: 300Mi
+ readinessProbe:
+ initialDelaySeconds: 20
+ periodSeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:9555"]
+ livenessProbe:
+ initialDelaySeconds: 20
+ periodSeconds: 15
+ exec:
+ command: ["/bin/grpc_health_probe", "-addr=:9555"]
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: adservice
+spec:
+ type: ClusterIP
+ selector:
+ app: adservice
+ ports:
+ - name: grpc
+ port: 9555
+ targetPort: 9555
+# [END gke_release_kubernetes_manifests_microservices_demo]
diff --git a/src/final-assessment/IaCSec/Kubernetes/kubernetes_service_account.yml b/src/final-assessment/IaCSec/Kubernetes/kubernetes_service_account.yml
new file mode 100644
index 0000000..f4f2424
--- /dev/null
+++ b/src/final-assessment/IaCSec/Kubernetes/kubernetes_service_account.yml
@@ -0,0 +1,44 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: vault-service-account
+ namespace: default
+
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: vault-role
+rules:
+- apiGroups: [""]
+ resources: ["pods", "deployments", "services", "replicationcontrollers", "persistentvolumes", "persistentvolumeclaims", "configmaps", "secrets", "serviceaccounts"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+- apiGroups: ["apps"]
+ resources: ["replicasets", "statefulsets", "daemonsets"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+- apiGroups: ["extensions"]
+ resources: ["ingresses"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+- apiGroups: ["batch"]
+ resources: ["jobs", "cronjobs"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+- apiGroups: ["authentication.k8s.io"]
+ resources: ["tokenreviews"]
+ verbs: ["create"]
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: vault-role-binding
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: vault-role
+subjects:
+- kind: ServiceAccount
+ name: vault-service-account
+ namespace: default
diff --git a/src/final-assessment/IaCSec/Kubernetes/pod_service_account.yml b/src/final-assessment/IaCSec/Kubernetes/pod_service_account.yml
new file mode 100644
index 0000000..e7f3045
--- /dev/null
+++ b/src/final-assessment/IaCSec/Kubernetes/pod_service_account.yml
@@ -0,0 +1,59 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: sa-pod
+ labels:
+ role: example-pod
+spec:
+ automountServiceAccountToken: false
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ serviceAccountName: vault-service-account
+ containers:
+ - name: ubuntu
+ #checkov:skip=CKV_K8S_43:No image digest
+ #checkov:skip=CKV_K8S_14:No image tag
+ image: ubuntu
+ env:
+ # - name: VAULT_ADDR
+ # value: "http://192.168.65.2:8200"
+ - name: VAULT_ROLE
+ value: internal-app
+ command: ["sleep", "infinity"]
+ securityContext:
+ readOnlyRootFilesystem: true
+ runAsUser: 20000
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ resources:
+ limits:
+ cpu: "0.5"
+ memory: "512Mi"
+ volumeMounts:
+ - name: shared-data
+ mountPath: /data
+ livenessProbe:
+ exec:
+ command:
+ - cat
+ - /tmp/healthy
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: 8080
+ initialDelaySeconds: 15
+ timeoutSeconds: 1
+ volumes:
+ - name: shared-data
+ emptyDir: {}
+
+
+
+
+
+
diff --git a/src/final-assessment/IaCSec/Kubernetes/setup_aks.sh b/src/final-assessment/IaCSec/Kubernetes/setup_aks.sh
new file mode 100644
index 0000000..f2f79b7
--- /dev/null
+++ b/src/final-assessment/IaCSec/Kubernetes/setup_aks.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+az login
+
+# Automatic configuration of local kubectl
+az aks get-credentials -g aks-resource-group -n aks-cluster
+
+kubectl get nodes
+
+# Deploy Service Account and Test Pod
+#kubectl apply -f ./kubernetes_service_account.yml
+#kubectl apply -f ./pod_service_account.yml
+
+# Deploy Online Boutique
+#kubectl apply -f ./kubernetes_manifest_edited.yml
+
+# Deploy Spring DB Connector microservice
+#kubectl apply -f ./db_connector_manifest.yml
+
+# Deploy Kubernetes Dashboard
+#kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
+
+echo "Dashboard URL: http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/"
+
+#Deploy Sysdig Agent
+# helm repo add sysdig https://charts.sysdig.com
+# helm repo update
+# helm install sysdig-agent --namespace sysdig-agent --create-namespace \
+# --set global.sysdig.accessKey=fd19e5cc-9261-4c5f-827e-bbc855c83861 \
+# --set global.sysdig.region=eu1 \
+# --set nodeAnalyzer.secure.vulnerabilityManagement.newEngineOnly=true \
+# --set global.kspm.deploy=true \
+# --set nodeAnalyzer.nodeAnalyzer.benchmarkRunner.deploy=false \
+# --set global.clusterConfig.name=aks-cluster \
+# sysdig/sysdig-deploy
+
+# Proxy access to kubernetes dashboard
+#kubectl proxy
+
+
+# Dashboard: http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/Kubernetes/test_pod.yml b/src/final-assessment/IaCSec/Kubernetes/test_pod.yml
new file mode 100644
index 0000000..63e926e
--- /dev/null
+++ b/src/final-assessment/IaCSec/Kubernetes/test_pod.yml
@@ -0,0 +1,52 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: ubuntu-curl-pod
+ labels:
+ role: example-pod
+spec:
+ automountServiceAccountToken: false
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ containers:
+ - name: ubuntu
+ image: ubuntu
+ #checkov:skip=CKV_K8S_43:No image digest
+ #checkov:skip=CKV_K8S_14:No image tag
+ command: ["sleep", "infinity"]
+ securityContext:
+ readOnlyRootFilesystem: true
+ runAsUser: 20000
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ livenessProbe:
+ exec:
+ command:
+ - cat
+ - /tmp/healthy
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: 8080
+ initialDelaySeconds: 15
+ timeoutSeconds: 1
+ resources:
+ limits:
+ cpu: "0.5"
+ memory: "512Mi"
+ volumeMounts:
+ - name: shared-data
+ mountPath: /data
+ volumes:
+ - name: shared-data
+ emptyDir: {}
+
+
+
+
+
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/.gitignore b/src/final-assessment/IaCSec/Vault-on-VM/.gitignore
new file mode 100644
index 0000000..7a3e2fd
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/.gitignore
@@ -0,0 +1,29 @@
+# Local .terraform directories
+**/.terraform/*
+
+# .tfstate files
+*.tfstate
+*.tfstate.*
+
+# Crash log files
+crash.log
+
+# Ignore any .tfvars files that are generated automatically for each Terraform run. Most
+# .tfvars files are managed as part of configuration and so should be included in
+# version control.
+#
+# example.tfvars
+
+# Ignore override files as they are usually used to override resources locally and so
+# are not checked in
+override.tf
+override.tf.json
+*_override.tf
+*_override.tf.json
+
+# Include override files you do wish to add to version control using negated pattern
+#
+# !example_override.tf
+
+# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
+# example: *tfplan*
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/.terraform.lock.hcl b/src/final-assessment/IaCSec/Vault-on-VM/.terraform.lock.hcl
new file mode 100644
index 0000000..b288be4
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/.terraform.lock.hcl
@@ -0,0 +1,118 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/azuread" {
+ version = "2.29.0"
+ constraints = "~> 2.29.0"
+ hashes = [
+ "h1:9iqybcju7yDZEQUpfAi4wMNX7JBi8VXgx8ktk7wjtJQ=",
+ "zh:049f0b90042679247ebe9ae8e4e7bbcadd0d8764a2d9f6b7c84b0985a0550da9",
+ "zh:0d1e0a64c36451b77a6208a02a586e4f39960adc1d2db867383adeafaaf170bb",
+ "zh:124a019672dcde52f98bc6f2160b764be92b1648b172e08d454a5e938e7d78fd",
+ "zh:1b7dae68749615039a3dd2fd00398f6a283eea79ae69843a7420da31937c14b9",
+ "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7",
+ "zh:3f119ac8244d58208e7e0ad24924ae7ea7e5b6f2b0049ddf79e9fbc13bbf4c5f",
+ "zh:59c8d53cf3a0c132fa4e1ee14358a4a1670af35c5a4ba4da8701cb6bce9b09fa",
+ "zh:5a4d0a6fe3f9d6e612e7bb1a4845c55efea906e09e4fd7b9883d67add27af1ab",
+ "zh:79c42325602cff91aabc8000fcece3f808b152b2e839c9add63c83cf60ed91fb",
+ "zh:a77b87f9fc87bb9fa892bb0a3fa695f3ad57dbd35831ead9dc8709bc5fc9f002",
+ "zh:ab5b1c823375aa5ee002081f72e28bd15cafecb47b546247b45fb3e165aa7bdb",
+ "zh:efa4091ed8f124d261b3771259f28ca70fd926096445c0d6457342cb2f72092d",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.52.0"
+ constraints = "3.52.0"
+ hashes = [
+ "h1:atlTwMcGXXF0rKzLNZhKj7djwoKT4b6in+xa2Hz09Y8=",
+ "zh:0c3029da7454f2fe7058939d95c458d9930842f06430cfcd0713713f3d788216",
+ "zh:826584f11eaaec7f179e85d9cc4833ec7a1d854ed4883c94317427ddfa7ffd11",
+ "zh:8fff204176ee1b08d168848d4bd7a051d7fd189688ca8b5f26eb31855ea060a6",
+ "zh:a170ebe199b93ea1f20357d848dfd0f5e50538236f09939d1a11a61dfbfded0f",
+ "zh:acea54d715186101f8a7725997578b231e4db50eea0fb9f9868ecd867008e6e6",
+ "zh:ae0f6a61677282a2f605ca9d0a74a08ae78ae2efeb372a33b9d4c7210fbbfd2c",
+ "zh:c2c2329f3864e10ee15993c1a48e79bf72d570bb6d08003038a37b73e551dbf9",
+ "zh:c7a4a117628ff0ad24e9c73f1087e9a02b8eca633b0913ee1687b0b4b5c7f377",
+ "zh:e1a290e708e7dbbde8747a98680f7a1aace97694a243ba7a11cc5c77e982e9cc",
+ "zh:e82aa1c5e8ead3087968d7f44b6f644ef3092a0d243b4b575ff8847616e290b3",
+ "zh:f4d57d3c5f3c7fe064b88151036037b7852be6bcfa661e3f4fe0fda2871006d9",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/local" {
+ version = "2.4.0"
+ hashes = [
+ "h1:7RnIbO3CFakblTJs7o0mUiY44dc9xGYsLhSNFSNS1Ds=",
+ "zh:53604cd29cb92538668fe09565c739358dc53ca56f9f11312b9d7de81e48fab9",
+ "zh:66a46e9c508716a1c98efbf793092f03d50049fa4a83cd6b2251e9a06aca2acf",
+ "zh:70a6f6a852dd83768d0778ce9817d81d4b3f073fab8fa570bff92dcb0824f732",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:82a803f2f484c8b766e2e9c32343e9c89b91997b9f8d2697f9f3837f62926b35",
+ "zh:9708a4e40d6cc4b8afd1352e5186e6e1502f6ae599867c120967aebe9d90ed04",
+ "zh:973f65ce0d67c585f4ec250c1e634c9b22d9c4288b484ee2a871d7fa1e317406",
+ "zh:c8fa0f98f9316e4cfef082aa9b785ba16e36ff754d6aba8b456dab9500e671c6",
+ "zh:cfa5342a5f5188b20db246c73ac823918c189468e1382cb3c48a9c0c08fc5bf7",
+ "zh:e0e2b477c7e899c63b06b38cd8684a893d834d6d0b5e9b033cedc06dd7ffe9e2",
+ "zh:f62d7d05ea1ee566f732505200ab38d94315a4add27947a60afa29860822d3fc",
+ "zh:fa7ce69dde358e172bd719014ad637634bbdabc49363104f4fca759b4b73f2ce",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+ version = "3.1.3"
+ constraints = "~> 3.1.2"
+ hashes = [
+ "h1:d4M8bOY9r99suD5EYfdZUvbhtq6hzCHa2SeY+T+IRlA=",
+ "zh:26e07aa32e403303fc212a4367b4d67188ac965c37a9812e07acee1470687a73",
+ "zh:27386f48e9c9d849fbb5a8828d461fde35e71f6b6c9fc235bc4ae8403eb9c92d",
+ "zh:5f4edda4c94240297bbd9b83618fd362348cadf6bf24ea65ea0e1844d7ccedc0",
+ "zh:646313a907126cd5e69f6a9fafe816e9154fccdc04541e06fed02bb3a8fa2d2e",
+ "zh:7349692932a5d462f8dee1500ab60401594dddb94e9aa6bf6c4c0bd53e91bbb8",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:9034daba8d9b32b35930d168f363af04cecb153d5849a7e4a5966c97c5dc956e",
+ "zh:bb81dfca59ef5f949ef39f19ea4f4de25479907abc28cdaa36d12ecd7c0a9699",
+ "zh:bcf7806b99b4c248439ae02c8e21f77aff9fadbc019ce619b929eef09d1221bb",
+ "zh:d708e14d169e61f326535dd08eecd3811cd4942555a6f8efabc37dbff9c6fc61",
+ "zh:dc294e19a46e1cefb9e557a7b789c8dd8f319beca99b8c265181bc633dc434cc",
+ "zh:f9d758ee53c55dc016dd736427b6b0c3c8eb4d0dbbc785b6a3579b0ffedd9e42",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/template" {
+ version = "2.2.0"
+ constraints = "~> 2.2.0"
+ hashes = [
+ "h1:LN84cu+BZpVRvYlCzrbPfCRDaIelSyEx/W9Iwwgbnn4=",
+ "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386",
+ "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53",
+ "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603",
+ "zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16",
+ "zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776",
+ "zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451",
+ "zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae",
+ "zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde",
+ "zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d",
+ "zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/tls" {
+ version = "4.0.4"
+ hashes = [
+ "h1:rKKMyIEBZwR+8j6Tx3PwqBrStuH+J+pxcbCR5XN8WAw=",
+ "zh:23671ed83e1fcf79745534841e10291bbf34046b27d6e68a5d0aab77206f4a55",
+ "zh:45292421211ffd9e8e3eb3655677700e3c5047f71d8f7650d2ce30242335f848",
+ "zh:59fedb519f4433c0fdb1d58b27c210b27415fddd0cd73c5312530b4309c088be",
+ "zh:5a8eec2409a9ff7cd0758a9d818c74bcba92a240e6c5e54b99df68fff312bbd5",
+ "zh:5e6a4b39f3171f53292ab88058a59e64825f2b842760a4869e64dc1dc093d1fe",
+ "zh:810547d0bf9311d21c81cc306126d3547e7bd3f194fc295836acf164b9f8424e",
+ "zh:824a5f3617624243bed0259d7dd37d76017097dc3193dac669be342b90b2ab48",
+ "zh:9361ccc7048be5dcbc2fafe2d8216939765b3160bd52734f7a9fd917a39ecbd8",
+ "zh:aa02ea625aaf672e649296bce7580f62d724268189fe9ad7c1b36bb0fa12fa60",
+ "zh:c71b4cd40d6ec7815dfeefd57d88bc592c0c42f5e5858dcc88245d371b4b8b1e",
+ "zh:dabcd52f36b43d250a3d71ad7abfa07b5622c69068d989e60b79b2bb4f220316",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/LICENSE b/src/final-assessment/IaCSec/Vault-on-VM/LICENSE
new file mode 100644
index 0000000..a612ad9
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/README.md b/src/final-assessment/IaCSec/Vault-on-VM/README.md
new file mode 100644
index 0000000..7a2dde3
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/README.md
@@ -0,0 +1,256 @@
+# Auto-unseal using Azure Key Vault
+
+These assets are provided to perform the tasks described in the [Auto-unseal with Azure Key Vault](https://learn.hashicorp.com/vault/operations/autounseal-azure-keyvault) guide.
+
+In addition, a script is provided so that you can enable and test `azure` auth method. (_Optional_)
+
+---
+
+## Prerequisites
+
+- Microsoft Azure account
+- [Terraform installed](https://www.terraform.io/downloads.html) and ready to use
+
+
+
+**Terraform Azure Provider Prerequisites**
+
+A ***service principal*** is an application within Azure Active Directory which
+can be used to authenticate. Service principals are preferable to running an app
+using your own credentials. Follow the instruction in the [Terraform
+documentation](https://www.terraform.io/docs/providers/azurerm/auth/service_principal_client_certificate.html)
+to create a service principal and then configure in Terraform.
+
+Tips:
+
+- **Subscription ID**: Navigate to the [Subscriptions blade within the Azure
+ Portal](https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade)
+ and copy the **Subscription ID**
+
+- **Tenant ID**: Navigate to the [Azure Active Directory >
+ Properties](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Properties)
+ in the Azure Portal, and copy the **Directory ID** which is your tenant ID
+
+- **Client ID**: Same as the [**Application
+ ID**](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ApplicationsListBlade)
+
+- **Client secret**: The [password
+ (credential)](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ApplicationsListBlade)
+ set on your application
+
+> **IMPORTANT:** Ensure that your Service Principal has appropriate permissions to provision virtual machines, networks, as well as **Azure Key Vault**. Refer to the [Azure documentation](https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal).
+
+## Auto-unseal Steps
+
+1. Set this location as your working directory
+
+1. Provide Azure credentials in the `terraform.tfvars.example` and save it as `terraform.tfvars`
+
+ > NOTE: Overwrite the Azure `location` or `environment` name in the `terraform.tfvars` as desired.
+
+1. Run the Terraform commands:
+
+ ```shell
+ # Pull necessary plugins
+ $ terraform init
+
+ $ terraform plan -out tfplan
+ ...
+ Outputs:
+
+ ip = 13.82.62.56
+ key_vault_name = Test-vault-1e5a88de
+ ssh-addr =
+ Connect to your virtual machine via SSH:
+
+ $ ssh azureuser@13.82.62.562
+ ```
+
+1. SSH into the virtual machine:
+
+ ```plaintext
+ $ ssh azureuser@13.82.62.562
+ ```
+
+1. Check the current Vault status:
+
+ ```text
+ $ vault status
+ Key Value
+ --- -----
+ Recovery Seal Type azurekeyvault
+ Initialized false
+ Sealed true
+ Total Recovery Shares 0
+ Threshold 0
+ Unseal Progress 0/0
+ Unseal Nonce n/a
+ Version n/a
+ HA Enabled false
+ ```
+
+ Vault hasn't been initialized, yet.
+
+1. Initialize Vault
+
+ ```plaintext
+ $ vault operator init
+
+ Recovery Key 1:
+ Recovery Key 2:
+ Recovery Key 3:
+ Recovery Key 4:
+ Recovery Key 5:
+
+ Initial Root Token:
+
+ Success! Vault is initialized
+
+ Recovery key initialized with 5 key shares and a key threshold of 3. Please
+ securely distribute the key shares printed above.
+ ```
+
+1. Stop and start the Vault server
+
+ ```shell
+ $ sudo systemctl restart vault
+ ```
+
+1. Check to verify that the Vault is auto-unsealed
+
+ ```text
+ $ vault status
+ Key Value
+ --- -----
+ Recovery Seal Type shamir
+ Initialized true
+ Sealed false
+ Total Recovery Shares 5
+ Threshold 3
+ Version 1.5.0
+ Cluster Name vault-cluster-092ba5de
+ Cluster ID 8b173565-7d74-fe5b-a199-a2b56b7019ee
+ HA Enabled false
+ ```
+
+1. Explore the Vault configuration file
+
+ ```plaintext
+ $ sudo cat /etc/vault.d/vault.hcl
+
+ ui = true
+ disable_mlock = true
+
+ api_addr = "http://VAULT-IP-ADDRESS:8200"
+ cluster_addr = "http://VAULT-IP-ADDRESS:8201"
+
+ storage "file" {
+ path = "/opt/vault/data"
+ }
+
+ listener "tcp" {
+ address = "0.0.0.0:8200"
+ cluster_address = "0.0.0.0:8201"
+ tls_disable = 1
+ telemetry {
+ unauthenticated_metrics_access = true
+ }
+ }
+
+ # enable the telemetry endpoint.
+ # access it at http://:8200/v1/sys/metrics?format=prometheus
+ # see https://www.vaultproject.io/docs/configuration/telemetry
+ # see https://www.vaultproject.io/docs/configuration/listener/tcp#telemetry-parameters
+ telemetry {
+ disable_hostname = true
+ prometheus_retention_time = "24h"
+ }
+
+ # enable auto-unseal using the azure key vault.
+ seal "azurekeyvault" {
+ client_id = "YOUR-AZURE-APP-ID"
+ client_secret = "YOUR-AZURE-APP-PASSWORD"
+ tenant_id = "YOUR-AZURE-TENANT-ID"
+ vault_name = "Test-vault-xxxx"
+ key_name = "generated-key"
+ }
+ ```
+
+## Azure Auth Method Steps
+
+The `azure` auth method allows authentication against Vault using Azure Active Directory credentials.
+
+1. First, log into Vault using the generated initial root token:
+
+ ```plaintext
+ $ vault login s.bRyEk2vIPrKfeldFZD5xFvUL
+ ```
+
+1. Explore the `/tmp/azure_auth.sh` file
+
+ ```plaintext
+ $ cat /tmp/azure_auth.sh
+ ```
+
+ This script performs the following:
+
+ - Enable the Azure auth method at `azure`
+ - Configure the Azure auth method
+ - Create a role named `dev-role` with `default` policy
+ - Finally, log into Vault using as `dev-role` to obtain a Vault client token
+
+1. Execute the script
+
+ ```plaintext
+ $ /tmp/azure_auth.sh
+ ...
+ Key Value
+ --- -----
+ token s.xYqTKUSivsKiwNwXv6wz9LUJ
+ token_accessor 0dua5lTuYkAyQakJiy0oKJW5
+ token_duration 768h
+ token_renewable true
+ token_policies ["default"]
+ identity_policies []
+ policies ["default"]
+ token_meta_resource_group_name learn-vault-rg
+ token_meta_role dev-role
+ token_meta_subscription_id YOUR-AZURE-SUBSCRIPTION-ID
+ token_meta_vm_name azure-auth-demo-vm
+ ```
+
+ A valid service token is generated.
+
+ ```plaintext
+ $ vault token lookup s.xYqTKUSivsKiwNwXv6wz9LUJ
+
+ Key Value
+ --- -----
+ accessor 0dua5lTuYkAyQakJiy0oKJW5
+ creation_time 1548279674
+ creation_ttl 768h
+ display_name azure-cc47203d-6c51-4498-9c3d-5e2874eca6fb
+ entity_id 7009136d-2eee-0414-61f9-e705a9f299ef
+ expire_time 2019-02-24T21:41:14.231599224Z
+ explicit_max_ttl 0s
+ id s.xYqTKUSivsKiwNwXv6wz9LUJ
+ issue_time 2019-01-23T21:41:14.231598924Z
+ meta map[resource_group_name:learn-vault-rg role:dev-role subscription_id:YOUR-AZURE-SUBSCRIPTION-ID vm_name:azure-auth-demo-vm]
+ num_uses 0
+ orphan true
+ path auth/azure/login
+ policies [default]
+ renewable true
+ ttl 767h59m48s
+ type service
+ ```
+
+## Clean up
+
+Run `terraform destroy` when you are done exploring:
+
+```plaintext
+$ terraform destroy -auto-approve
+
+$ rm -rf .terraform terraform.tfstate*
+```
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/aks_ca.crt b/src/final-assessment/IaCSec/Vault-on-VM/aks_ca.crt
new file mode 100644
index 0000000..f331b4c
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/aks_ca.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE6DCCAtCgAwIBAgIQAof5BQJLoeMKk4seL/4c1zANBgkqhkiG9w0BAQsFADAN
+MQswCQYDVQQDEwJjYTAgFw0yMzA1MjMwOTIyNDRaGA8yMDUzMDUyMzA5MzI0NFow
+DTELMAkGA1UEAxMCY2EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo
+mtCDZCc53g0W4/dsS+RC+P0Kf3k1PUEm4tnAjQi0fNXCQ+X6k91vB8fnuk/4hy3C
+9H1J1c6zOI4Ln2rqpsJZINXc9AU56Sc56xpPWW/53K6jcerw0DQcg/j7Uc3ocimh
+ajXfYr2v+ktrcKgO9Idz1+t0F45uXD4ya65c+eV6//Taeti2CWvKAqBYacPqsC2o
+8pKxa/x0BF0HPgCRgeZ8FCqyvQPw1yRXhO/DEA9qoJa4YhLZgdEMYIlmcjeat/SQ
+jneljh2zZgAKDkrrunz8etzq2DwljA+SnsgXe00qUdkt9SGLdSdnBi10K6DkcDPe
+gLjbtlEe2ddRwJtJ7ukZ+0LqUZgDNlBb3qpOGDrNMgM+TPhkMEwo7Z+nwmrqHZBo
+flZUrWoYM3bgKDqSt72WmgnL7GOXtOigG9lFOlNqM3IywpLtPHoEIm/4vRCpJLh0
+0wVOaN4U+95uctdcYhp670TD3m4bGgn5Wj7yzNgbWUHJhfqr0V0ddSlUoXB0/9OE
++5UvdQEhPe85wHqREsQF54sfKtzYGyKS7B4OWd8CrN21n8GbZbzwpOEgca+MHWhk
+7CX5Hen2sDLOgPR01yj9calededRWJBFVne4iKcSwkq1vJ00E0UnLbIbwz7edIid
+PCxXDLjSZ9MnAMyvPFYipzHb/qB/FzbZDmGlUuf4ZQIDAQABo0IwQDAOBgNVHQ8B
+Af8EBAMCAqQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUmeikroaB4YU84nNx
+JNJ1pU5I/TcwDQYJKoZIhvcNAQELBQADggIBAAmtxyNlMwixMEm2XQU3afV1bCZc
+17yH9u4Yvt6uWxpgh7nlNGep2/Jxp+cCHGmVo4OyIAOgSutvLEKkBpCUWltOVgIq
+ECQ9sSI4YEv8c+LiPzwMgMkUijs9lR6gXYNtwTH3KGAl6IG63jXjRwbFE0TSN3Kx
+CMpXC74/y6VzjPknqHBvljdEB1Ql/qhsc/OukMKnLQ7sG4QlaGqI4suUqPdWv8jV
+XyLsR3PdBncWmu2yM53ndG0Ru/QNqHiCbn8YjB0eG6JlhJFhVy52OotewqOymkz1
+/RuUJFeIwTdRr/q3NmRTrJF8PlFhM+29rH1QxJv2KK4I67pAxUFHUV7ycqmIWq5/
+jkivEsBxO+HxJRgGtW6EipJ72SdLBQUys1Ng9YyJbgX7pnWIlXhIFeVDHzVoeUZj
+B3Rhnsu0mVkEqXC1To0FldeU8xptJXkVhPccPkR6WO4Opbx9uY5PrcrnbOrj5IkE
+rIZhX6VNN19O9k+swDiw/ukBhxkvqTdZn5MFuVZMmJ1zM2GgaSNmCFCThQr3wud5
+Ms5gUWJ3DkJ85v4KEDDGv5cqptjr3C9Q/pY58MlBnCf/nIGHxVvClIp8pA4oxIFM
+2mlaj6GR+pbHVy0hrFefJWvFLr7AxGRdSBpzOPcobP5FrVAj0fYju2mieFMe6bET
+7jb5XBY607kGKip2
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/main.tf b/src/final-assessment/IaCSec/Vault-on-VM/main.tf
new file mode 100644
index 0000000..bd36dcd
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/main.tf
@@ -0,0 +1,443 @@
+# see https://github.com/hashicorp/terraform
+terraform {
+ required_version = ">= 1.1.7"
+ required_providers {
+ template = "~> 2.2.0"
+ random = "~> 3.1.2"
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "3.52.0"
+ }
+ azuread = "~> 2.29.0"
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform"
+ storage_account_name = "terraformstate1603709092"
+ container_name = "tfstate"
+ key = "terraform.tfstate_vault_vm"
+ }
+}
+
+# see https://github.com/terraform-providers/terraform-provider-azurerm
+provider "azurerm" {
+ subscription_id = var.credentials["subscription_id"]
+ client_id = var.credentials["client_id"]
+ client_secret = var.azure_sp_key
+ tenant_id = var.credentials["tenant_id"]
+ features {}
+}
+
+
+
+
+resource "azurerm_resource_group" "vault" {
+ name = var.resource_group_name
+ location = var.location
+}
+
+resource "random_id" "keyvault" {
+ byte_length = 4
+}
+
+data "azurerm_client_config" "current" {
+}
+
+data "azuread_service_principal" "vault" {
+ application_id = var.client_id
+}
+
+############################
+ # CERTIFICATES
+############################
+
+resource "tls_private_key" "private" {
+ algorithm = "RSA"
+ rsa_bits = 4096
+}
+
+resource "tls_self_signed_cert" "cert" {
+ private_key_pem = tls_private_key.private.private_key_pem
+ validity_period_hours = 87600
+
+ # Reasonable set of uses for a server SSL certificate.
+ allowed_uses = [
+ "key_encipherment",
+ "digital_signature",
+ "server_auth",
+ ]
+
+ ip_addresses = [
+ "127.0.0.1"
+ ]
+
+ dns_names = ["${azurerm_key_vault.vault.name}.${var.location}.azurecontainer.io"]
+
+ subject {
+ common_name = "${azurerm_key_vault.vault.name}.${var.location}.azurecontainer.io"
+ organization = "Test Organization, Inc"
+ }
+}
+
+resource "local_file" "key" {
+ content = tls_private_key.private.private_key_pem
+ filename = "${path.module}/vault-cert.key"
+}
+
+resource "local_file" "cert" {
+ content = tls_self_signed_cert.cert.cert_pem
+ filename = "${path.module}/vault-cert.crt"
+}
+
+
+
+ ###########################
+ # VAULT
+ ###########################
+
+resource "azurerm_key_vault" "vault" {
+ name = "azure-vault-${random_id.keyvault.hex}"
+ location = azurerm_resource_group.vault.location
+ resource_group_name = azurerm_resource_group.vault.name
+ tenant_id = var.tenant_id
+ public_network_access_enabled = false
+ purge_protection_enabled = true
+ soft_delete_retention_days = 7
+
+ # enable virtual machines to access this key vault.
+ # NB this identity is used in the example /tmp/azure_auth.sh file.
+ # vault is actually using the vault service principal.
+ enabled_for_deployment = true
+
+ sku_name = "standard"
+
+ # access policy for the hashicorp vault service principal.
+ access_policy {
+ tenant_id = var.tenant_id
+ object_id = data.azuread_service_principal.vault.object_id
+
+ key_permissions = [
+ "Get", "List", "Create", "Delete", "Update", "WrapKey", "UnwrapKey", "GetRotationPolicy", "Purge",
+ ]
+ }
+
+ # access policy for the user that is currently running terraform.
+ access_policy {
+ tenant_id = var.tenant_id
+ object_id = data.azurerm_client_config.current.object_id
+
+ key_permissions = [
+ "Get", "List", "Create", "Delete", "Update", "WrapKey", "UnwrapKey", "GetRotationPolicy", "Purge",
+ ]
+ }
+
+ # TODO does this really need to be so broad? can it be limited to the vault vm?
+ # network_acls {
+ # default_action = "Allow"
+ # bypass = "AzureServices"
+ # }
+
+ network_acls {
+ default_action = "Deny"
+ bypass = "AzureServices"
+ virtual_network_subnet_ids = [
+ azurerm_subnet.tf_subnet.id
+ ]
+ }
+}
+
+# TODO the "generated" resource name is not very descriptive; why not use "vault" instead?
+# hashicorp vault will use this azurerm_key_vault_key to wrap/encrypt its master key.
+resource "azurerm_key_vault_key" "generated" {
+ name = var.key_name
+ key_vault_id = azurerm_key_vault.vault.id
+ key_type = "RSA-HSM"
+ key_size = 2048
+ expiration_date = "2030-12-30T20:00:00Z"
+
+ key_opts = [
+ "decrypt",
+ "encrypt",
+ "sign",
+ "unwrapKey",
+ "verify",
+ "wrapKey",
+ ]
+}
+
+output "key_vault_name" {
+ value = azurerm_key_vault.vault.name
+}
+
+############################
+ # VAULT VM NEEDED RESOURCES
+############################
+resource "azurerm_virtual_network" "tf_network" {
+ name = "network-${random_id.keyvault.hex}"
+ address_space = ["10.0.0.0/16"]
+ location = var.location
+ resource_group_name = azurerm_resource_group.vault.name
+}
+
+resource "azurerm_subnet" "tf_subnet" {
+ name = "subnet-${random_id.keyvault.hex}"
+ resource_group_name = azurerm_resource_group.vault.name
+ virtual_network_name = azurerm_virtual_network.tf_network.name
+ address_prefixes = ["10.0.1.0/24"]
+}
+
+resource "azurerm_public_ip" "tf_publicip" {
+ name = "ip-${random_id.keyvault.hex}"
+ location = var.location
+ resource_group_name = azurerm_resource_group.vault.name
+ allocation_method = "Dynamic"
+}
+
+resource "azurerm_network_security_group" "tf_nsg" {
+ name = "nsg-${random_id.keyvault.hex}"
+ location = var.location
+ resource_group_name = azurerm_resource_group.vault.name
+
+ # security_rule {
+ # name = "SSH"
+ # priority = 1001
+ # direction = "Inbound"
+ # access = "Allow"
+ # protocol = "Tcp"
+ # source_port_range = "*"
+ # destination_port_range = "22"
+ # source_address_prefix = "*"
+ # destination_address_prefix = "*"
+ # }
+
+ security_rule {
+ name = "Vault"
+ priority = 1002
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "Tcp"
+ source_port_range = "*"
+ destination_port_range = "8200"
+ source_address_prefix = "*"
+ destination_address_prefix = "*"
+ }
+
+ security_rule {
+ name = "Consul"
+ priority = 1003
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "Tcp"
+ source_port_range = "*"
+ destination_port_range = "8500"
+ source_address_prefix = "*"
+ destination_address_prefix = "*"
+ }
+}
+
+resource "azurerm_network_interface" "tf_nic" {
+ name = "nic-${random_id.keyvault.hex}"
+ location = var.location
+ resource_group_name = azurerm_resource_group.vault.name
+
+ ip_configuration {
+ name = "nic-${random_id.keyvault.hex}"
+ subnet_id = azurerm_subnet.tf_subnet.id
+ private_ip_address_allocation = "Dynamic"
+ public_ip_address_id = azurerm_public_ip.tf_publicip.id
+ }
+}
+
+resource "azurerm_network_interface_security_group_association" "tf_nisga" {
+ network_interface_id = azurerm_network_interface.tf_nic.id
+ network_security_group_id = azurerm_network_security_group.tf_nsg.id
+}
+
+resource "azurerm_subnet_network_security_group_association" "example" {
+ subnet_id = azurerm_subnet.tf_subnet.id
+ network_security_group_id = azurerm_network_security_group.tf_nsg.id
+}
+
+resource "random_id" "tf_random_id" {
+ keepers = {
+ # Generate a new ID only when a new resource group is defined
+ resource_group = azurerm_resource_group.vault.name
+ }
+
+ byte_length = 8
+}
+
+############################
+ # STORAGE ACCOUNT AND FILE SHARE
+############################
+
+resource "azurerm_storage_account" "tf_storageaccount" {
+ name = "sa${random_id.keyvault.hex}"
+ resource_group_name = azurerm_resource_group.vault.name
+ location = var.location
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+ public_network_access_enabled = false
+ allow_nested_items_to_be_public = false
+
+ network_rules {
+ default_action = "Deny"
+ bypass = "AzureServices"
+ ip_rules = "0.0.0.0/0"
+ }
+}
+
+resource "azurerm_storage_share" "vault" {
+ name = "vault-data"
+ storage_account_name = azurerm_storage_account.tf_storageaccount.name
+ quota = 5
+ depends_on = [
+ azurerm_storage_account.tf_storageaccount
+ ]
+}
+
+############################
+ # FILE SHARE DIRECTORY
+############################
+
+resource "azurerm_storage_share_directory" "vault" {
+ name = "certs"
+ share_name = azurerm_storage_share.vault.name
+ storage_account_name = azurerm_storage_account.tf_storageaccount.name
+ depends_on = [
+ azurerm_storage_share.vault
+ ]
+}
+
+############################
+ # VM TEMPLATE FILE
+############################
+
+data "template_file" "setup" {
+ template = file("${path.module}/setup.tpl")
+
+ vars = {
+ resource_group_name = "vault-vm-rg"
+ vm_name = var.vm_name
+ vault_version = var.vault_version
+ tenant_id = var.tenant_id
+ subscription_id = var.subscription_id
+ client_id = var.client_id
+ client_secret = var.client_secret
+ vault_name = azurerm_key_vault.vault.name
+ key_name = var.key_name
+ }
+}
+
+############################
+ # STORAGE ACCOUNT UAI
+############################
+
+# resource "azurerm_user_assigned_identity" "storage-uai" {
+# name = "storage-uai"
+# location = var.location
+# resource_group_name = var.resource_group_name
+# depends_on = [
+# azurerm_resource_group.vault
+# ]
+# }
+
+# resource "azurerm_role_assignment" "storage-uai-assignment" {
+# role_definition_name = "Contributor"
+# scope = azurerm_storage_account.tf_storageaccount.id
+# principal_id = azurerm_user_assigned_identity.storage-uai.principal_id
+# depends_on = [
+# azurerm_user_assigned_identity.storage-uai
+# ]
+# }
+
+############################
+ # VM EXTENSION TO AUTOMATICALLY MOUNT FILESHARE
+############################
+
+resource "azurerm_virtual_machine_extension" "vm-extension" {
+ name = "mountfileshare"
+ virtual_machine_id = azurerm_linux_virtual_machine.tf_vm.id
+ publisher = "Microsoft.Azure.Extensions"
+ type = "CustomScript"
+ type_handler_version = "2.0"
+
+ settings = </etc/vault.d/vault.hcl <:8200/v1/sys/metrics?format=prometheus
+# see https://www.vaultproject.io/docs/configuration/telemetry
+# see https://www.vaultproject.io/docs/configuration/listener/tcp#telemetry-parameters
+telemetry {
+ disable_hostname = true
+ prometheus_retention_time = "24h"
+}
+
+# enable auto-unseal using the azure key vault.
+seal "azurekeyvault" {
+ client_id = "${client_id}"
+ client_secret = "${client_secret}"
+ tenant_id = "${tenant_id}"
+ vault_name = "${vault_name}"
+ key_name = "${key_name}"
+}
+EOF
+systemctl enable vault
+systemctl restart vault
+
+cat >/etc/profile.d/vault.sh <<'EOF'
+export VAULT_ADDR=http://127.0.0.1:8200
+export VAULT_SKIP_VERIFY=true
+EOF
+
+# TODO why isn't this in $HOME?
+cat >/tmp/azure_auth.sh <<'EOF'
+#!/bin/bash
+set -euxo pipefail
+
+# for more information see:
+# * https://www.vaultproject.io/docs/auth/azure
+# * https://www.vaultproject.io/api/auth/azure
+
+vault auth enable azure
+
+vault write auth/azure/config \
+ tenant_id="${tenant_id}" \
+ resource="https://management.azure.com/" \
+ client_id="${client_id}" \
+ client_secret="${client_secret}"
+
+vault write auth/azure/role/dev-role \
+ policies="default" \
+ bound_subscription_ids="${subscription_id}" \
+ bound_resource_groups="${resource_group_name}"
+
+# create a vault login token for the current virtual machine identity (as
+# returned by the azure instance metadata service).
+# NB use the returned token to login into vault using `vault login`.
+# see https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token
+# see https://docs.microsoft.com/en-us/azure/virtual-machines/linux/instance-metadata-service
+vault write auth/azure/login \
+ role="dev-role" \
+ jwt="$(curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -H Metadata:true -s | jq -r .access_token)" \
+ subscription_id="${subscription_id}" \
+ resource_group_name="${resource_group_name}" \
+ vm_name="${vm_name}"
+EOF
+chmod +x /tmp/azure_auth.sh
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/terraform.tfvars b/src/final-assessment/IaCSec/Vault-on-VM/terraform.tfvars
new file mode 100644
index 0000000..9d3d3ca
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/terraform.tfvars
@@ -0,0 +1,29 @@
+#------------
+# Required
+#------------
+
+# Provide your tenant ID (Required)
+tenant_id=""
+
+# Public SSH key (Required)
+public_key = ""
+
+# Azure Client ID (Required)
+client_id = ""
+
+# Azure Client secret (Required)
+client_secret = ""
+
+# Azure account subscription ID (Required)
+subscription_id = ""
+
+
+#------------
+# Optional
+#------------
+
+# To overwrite the default (Optional)
+# location="westus"
+
+# To overwrite the default (Optional)
+# environment = "test"
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/terraform.tfvars.example b/src/final-assessment/IaCSec/Vault-on-VM/terraform.tfvars.example
new file mode 100644
index 0000000..872e3d4
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/terraform.tfvars.example
@@ -0,0 +1,16 @@
+#------------
+# Required
+#------------
+
+
+
+
+#------------
+# Optional
+#------------
+
+# To overwrite the default (Optional)
+# location="westus"
+
+# To overwrite the default (Optional)
+# environment = "test"
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/tfplan b/src/final-assessment/IaCSec/Vault-on-VM/tfplan
new file mode 100644
index 0000000..3647598
Binary files /dev/null and b/src/final-assessment/IaCSec/Vault-on-VM/tfplan differ
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/variables.tf b/src/final-assessment/IaCSec/Vault-on-VM/variables.tf
new file mode 100644
index 0000000..0b2b1a7
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/variables.tf
@@ -0,0 +1,63 @@
+# ---------------------------
+# Azure Key Vault
+# ---------------------------
+variable "tenant_id" {
+ default = ""
+}
+
+variable "key_name" {
+ description = "Azure Key Vault key name"
+ default = "generated-key"
+}
+
+variable "location" {
+ description = "Azure location where the Key Vault resource to be created"
+ default = "uksouth"
+}
+
+variable "resource_group_name" {
+ type = string
+ default = "vault-vm-rg"
+}
+
+
+# ---------------------------
+# Virtual Machine
+# ---------------------------
+variable "public_key" {
+ default = ""
+}
+
+variable "subscription_id" {
+ default = ""
+}
+
+variable "client_id" {
+ default = ""
+}
+
+variable "client_secret" {
+ default = ""
+}
+
+variable "vm_name" {
+ default = "vault-vm"
+}
+
+variable "vault_version" {
+ # NB execute `apt-cache madison vault` to known the available versions.
+ default = "1.9.4"
+}
+
+variable "azure_sp_key" {}
+
+variable "credentials" {
+ description = "Azure Service Provider Credentials"
+ type = map(string)
+ default = {
+ subscription_id = "8eb30f69-69f6-4ff0-99ea-f9edd2274036"
+ tenant_id = "2a05ac92-2049-4a26-9b34-897763efc8e2"
+ client_id = "12d6c386-4977-4aea-9b56-902c514c9d14"
+ }
+}
+
diff --git a/src/final-assessment/IaCSec/Vault-on-VM/versions.tf b/src/final-assessment/IaCSec/Vault-on-VM/versions.tf
new file mode 100644
index 0000000..ac97c6a
--- /dev/null
+++ b/src/final-assessment/IaCSec/Vault-on-VM/versions.tf
@@ -0,0 +1,4 @@
+
+terraform {
+ required_version = ">= 0.12"
+}
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/.terraform.lock.hcl b/src/final-assessment/IaCSec/aws-infrastructure/.terraform.lock.hcl
new file mode 100644
index 0000000..e9ce808
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/.terraform.lock.hcl
@@ -0,0 +1,85 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "4.67.0"
+ constraints = ">= 3.28.0, >= 3.72.0, >= 3.73.0, ~> 4.44, >= 4.45.0"
+ hashes = [
+ "h1:LfOuBkdYCzQhtiRvVIxdP/KGJODa3cRsKjn8xKCTbVY=",
+ "zh:0843017ecc24385f2b45f2c5fce79dc25b258e50d516877b3affee3bef34f060",
+ "zh:19876066cfa60de91834ec569a6448dab8c2518b8a71b5ca870b2444febddac6",
+ "zh:24995686b2ad88c1ffaa242e36eee791fc6070e6144f418048c4ce24d0ba5183",
+ "zh:4a002990b9f4d6d225d82cb2fb8805789ffef791999ee5d9cb1fef579aeff8f1",
+ "zh:559a2b5ace06b878c6de3ecf19b94fbae3512562f7a51e930674b16c2f606e29",
+ "zh:6a07da13b86b9753b95d4d8218f6dae874cf34699bca1470d6effbb4dee7f4b7",
+ "zh:768b3bfd126c3b77dc975c7c0e5db3207e4f9997cf41aa3385c63206242ba043",
+ "zh:7be5177e698d4b547083cc738b977742d70ed68487ce6f49ecd0c94dbf9d1362",
+ "zh:8b562a818915fb0d85959257095251a05c76f3467caa3ba95c583ba5fe043f9b",
+ "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+ "zh:9c385d03a958b54e2afd5279cd8c7cbdd2d6ca5c7d6a333e61092331f38af7cf",
+ "zh:b3ca45f2821a89af417787df8289cb4314b273d29555ad3b2a5ab98bb4816b3b",
+ "zh:da3c317f1db2469615ab40aa6baba63b5643bae7110ff855277a1fb9d8eb4f2c",
+ "zh:dc6430622a8dc5cdab359a8704aec81d3825ea1d305bbb3bbd032b1c6adfae0c",
+ "zh:fac0d2ddeadf9ec53da87922f666e1e73a603a611c57bcbc4b86ac2821619b1d",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/cloudinit" {
+ version = "2.3.2"
+ constraints = ">= 2.0.0"
+ hashes = [
+ "h1:2jb+BfT5T96dXxUD2LQ6MtVHpXErd7ZybmMvdWE2jd4=",
+ "zh:2487e498736ed90f53de8f66fe2b8c05665b9f8ff1506f751c5ee227c7f457d1",
+ "zh:3d8627d142942336cf65eea6eb6403692f47e9072ff3fa11c3f774a3b93130b3",
+ "zh:434b643054aeafb5df28d5529b72acc20c6f5ded24decad73b98657af2b53f4f",
+ "zh:436aa6c2b07d82aa6a9dd746a3e3a627f72787c27c80552ceda6dc52d01f4b6f",
+ "zh:458274c5aabe65ef4dbd61d43ce759287788e35a2da004e796373f88edcaa422",
+ "zh:54bc70fa6fb7da33292ae4d9ceef5398d637c7373e729ed4fce59bd7b8d67372",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:893ba267e18749c1a956b69be569f0d7bc043a49c3a0eb4d0d09a8e8b2ca3136",
+ "zh:95493b7517bce116f75cdd4c63b7c82a9d0d48ec2ef2f5eb836d262ef96d0aa7",
+ "zh:9ae21ab393be52e3e84e5cce0ef20e690d21f6c10ade7d9d9d22b39851bfeddc",
+ "zh:cc3b01ac2472e6d59358d54d5e4945032efbc8008739a6d4946ca1b621a16040",
+ "zh:f23bfe9758f06a1ec10ea3a81c9deedf3a7b42963568997d84a5153f35c5839a",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/kubernetes" {
+ version = "2.22.0"
+ constraints = ">= 2.10.0"
+ hashes = [
+ "h1:EBi28mEwbQJXL25oZCMaPrOUvMm6fukV5hUPleKY2w0=",
+ "zh:1eac662b1f238042b2068401e510f0624efaf51fd6a4dd9c49d710a49d383b61",
+ "zh:4c35651603493437b0b13e070148a330c034ac62c8967c2de9da6620b26adca4",
+ "zh:50c0e8654efb46e3a3666c638ca2e0c8aec07f985fbc80f9205bed960386dc9b",
+ "zh:5f65194ddd6ea7e89b378297d882083a4b84962edb35dd35752f0c7e9d6282a0",
+ "zh:6fc0c2d65864324edde4db84f528268065df58229fc3ee321626687b0e603637",
+ "zh:73c58d007aba7f67c0aa9029794e10c2517bec565b7cb57d0f5948ea3f30e407",
+ "zh:7d6fc9d3c1843baccd2e1fc56317925a2f9df372427d30fcb5052d123adc887a",
+ "zh:a0ad9eb863b51586ea306c5f2beef74476c96684aed41a3ee99eb4b6d8898d01",
+ "zh:e218fcfbf4994ff741408a023a9d9eb6c697ce9f63ce5540d3b35226d86c963e",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ "zh:f95625f317795f0e38cc6293dd31c85863f4e225209d07d1e233c50d9295083c",
+ "zh:f96e0923a632bc430267fe915794972be873887f5e761ed11451d67202e256c8",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/tls" {
+ version = "4.0.4"
+ constraints = ">= 3.0.0"
+ hashes = [
+ "h1:rKKMyIEBZwR+8j6Tx3PwqBrStuH+J+pxcbCR5XN8WAw=",
+ "zh:23671ed83e1fcf79745534841e10291bbf34046b27d6e68a5d0aab77206f4a55",
+ "zh:45292421211ffd9e8e3eb3655677700e3c5047f71d8f7650d2ce30242335f848",
+ "zh:59fedb519f4433c0fdb1d58b27c210b27415fddd0cd73c5312530b4309c088be",
+ "zh:5a8eec2409a9ff7cd0758a9d818c74bcba92a240e6c5e54b99df68fff312bbd5",
+ "zh:5e6a4b39f3171f53292ab88058a59e64825f2b842760a4869e64dc1dc093d1fe",
+ "zh:810547d0bf9311d21c81cc306126d3547e7bd3f194fc295836acf164b9f8424e",
+ "zh:824a5f3617624243bed0259d7dd37d76017097dc3193dac669be342b90b2ab48",
+ "zh:9361ccc7048be5dcbc2fafe2d8216939765b3160bd52734f7a9fd917a39ecbd8",
+ "zh:aa02ea625aaf672e649296bce7580f62d724268189fe9ad7c1b36bb0fa12fa60",
+ "zh:c71b4cd40d6ec7815dfeefd57d88bc592c0c42f5e5858dcc88245d371b4b8b1e",
+ "zh:dabcd52f36b43d250a3d71ad7abfa07b5622c69068d989e60b79b2bb4f220316",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/example-pod.yaml b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/example-pod.yaml
new file mode 100644
index 0000000..324e182
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/example-pod.yaml
@@ -0,0 +1,44 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: ubuntu-pod
+ labels:
+ role: example-pod
+spec:
+ automountServiceAccountToken: false
+ securityContext:
+ seccompProfile:
+ type: RuntimeDefault
+ containers:
+ - name: ubuntu-container
+ #checkov:skip=CKV_K8S_43:No image digest
+ #checkov:skip=CKV_K8S_14:No image tag
+ image: ubuntu:latest
+ securityContext:
+ readOnlyRootFilesystem: true
+ allowPrivilegeEscalation: false
+ runAsUser: 20000
+ capabilities:
+ drop:
+ - ALL
+ livenessProbe:
+ exec:
+ command:
+ - cat
+ - /tmp/healthy
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: 8080
+ initialDelaySeconds: 15
+ timeoutSeconds: 1
+ resources:
+ requests:
+ cpu: 200m
+ memory: 180Mi
+ limits:
+ cpu: 300m
+ memory: 300Mi
+ command: ["sleep", "3600"]
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/sarolebinding.yaml b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/sarolebinding.yaml
new file mode 100644
index 0000000..c0fe0c3
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/sarolebinding.yaml
@@ -0,0 +1,13 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: my-service-account-binding
+subjects:
+- kind: ServiceAccount
+ name: my-service-account
+ namespace: default # Replace with your desired namespace
+roleRef:
+ kind: ClusterRole
+ name: cluster-admin # Replace with the desired ClusterRole (or create your own)
+ apiGroup: rbac.authorization.k8s.io
+
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/serviceaccount.yaml b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/serviceaccount.yaml
new file mode 100644
index 0000000..eea07f5
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/serviceaccount.yaml
@@ -0,0 +1,5 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: my-service-account
+ namespace: default
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/token b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/token
new file mode 100644
index 0000000..fc430cd
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/cluster-aux-resources/token
@@ -0,0 +1 @@
+eyJhbGciOiJSUzI1NiIsImtpZCI6ImE0YWMyNzZiZTc5ZWQ5ZTA4YjM3ODg2YWNlZGEwNDM5ZGNiMDhjNmIifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjIl0sImV4cCI6MTY5MTQ5MjMwNSwiaWF0IjoxNjkxNDg4NzA1LCJpc3MiOiJodHRwczovL29pZGMuZWtzLmV1LXdlc3QtMy5hbWF6b25hd3MuY29tL2lkLzI4RjZEQkM1MUNDMTU0QkRENThDRDE1QkIyNjBDNTBDIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6Im15LXNlcnZpY2UtYWNjb3VudCIsInVpZCI6ImFkNDk3NGVlLTFhZDEtNDFjZi05ODJjLWZmNDBlOGI1YThkYiJ9fSwibmJmIjoxNjkxNDg4NzA1LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpteS1zZXJ2aWNlLWFjY291bnQifQ.LoOQTJpw_g80KvVSeUFRqtEYdtiGg69cw07iI1borIQ-KPBYC3y-QBD9iUjIr3Kytc7hSTd-b4OrMQQDpWOdXcxx24LjjNIWssb2Mm3LNnW8c0xi1Cr0wRdOu7gNWkq79L7zDeZdhS8mIQZHR9CQJzCFsIhDuTP1zU_IVbfCj9-UZHstQJ03I5JhYEdWlsje7bpV8wE07wenOxiCJzCrQMtvNDCxl6PUuadSRha6Hn5UhFtZ0O6TP4EsDeVLStf8v_FpMdppGwr3vy9GpOVwnmyXBdl51TIm4YxbKyXhoYNxD9QCbioTpjYTTWTfNPNCTXd1I0bDs7sV3puK3kfArA
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/data.tf b/src/final-assessment/IaCSec/aws-infrastructure/data.tf
new file mode 100644
index 0000000..660d166
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/data.tf
@@ -0,0 +1,3 @@
+data "aws_availability_zones" "avzs" {
+ all_availability_zones = true
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/eks_module.tf b/src/final-assessment/IaCSec/aws-infrastructure/eks_module.tf
new file mode 100644
index 0000000..1b5f2e0
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/eks_module.tf
@@ -0,0 +1,67 @@
+#tfsec:ignore:aws-ec2-no-public-egress-sgr
+#tfsec:ignore:aws-eks-no-public-cluster-access
+#tfsec:ignore:aws-eks-no-public-cluster-access-to-cidr
+module "eks" {
+ source = "registry.terraform.io/terraform-aws-modules/eks/aws"
+ version = "19.0.4"
+
+ cluster_name = var.eks_cluster_name
+
+ iam_role_name = "${var.eks_cluster_name}-cluster"
+ iam_role_tags = {
+ Name = "${var.eks_cluster_name}-cluster"
+ }
+
+ vpc_id = module.vpc.vpc_id
+ subnet_ids = [
+ module.vpc.public_subnets[0],
+ module.vpc.public_subnets[1]
+ ]
+
+ eks_managed_node_groups = {
+ private-nodes = {
+ create = true
+ capacity_type = "ON_DEMAND"
+ instance_types = ["t3a.medium"]
+ desired_size = 1
+ max_size = 2
+ min_size = 1
+ iam_role_additional_policies = {
+ "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
+ }
+ }
+ }
+
+ cluster_endpoint_public_access = true
+ enable_irsa = false
+ cluster_enabled_log_types = ["api", "authenticator", "audit", "scheduler", "controllerManager"]
+
+
+ # node_security_group_additional_rules = {
+ # egress_all = {
+ # description = "Allow egress only inside the vpc and to other AWS IPs"
+ # protocol = "-1"
+ # from_port = 0
+ # to_port = 65535
+ # type = "egress"
+ # cidr_blocks = [module.vpc.vpc_cidr_block, "16.12.18.0/23", "16.12.20.0/24", "3.5.224.0/22", "52.95.154.0/23", "52.95.156.0/24"]
+ # }
+ # # FORSE NON HAI AGGIUNTO LA VIOLATION -> "CRITICAL Security group rule allows egress to multiple public internet addresses"
+ # }
+ create_cloudwatch_log_group = false
+
+
+ cluster_addons = {
+ "vpc-cni" = {
+ addon_version = "v1.12.5-eksbuild.2"
+ resolve_conflicts = "OVERWRITE"
+ }
+ }
+
+ tags = {
+ LAB = "tesi_manuel"
+ infra = "terraform"
+ }
+}
+
+
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/main.tf b/src/final-assessment/IaCSec/aws-infrastructure/main.tf
new file mode 100644
index 0000000..0781dbf
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/main.tf
@@ -0,0 +1,33 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.44"
+ }
+ }
+ backend "s3" {
+ bucket = "thesis-manuel-terraform-state-sysdig"
+ key = "terraform/eks-state/tfstate.json"
+ access_key = var.backend_access_key
+ secret_key = var.backend_secret_key
+ region = "eu-west-3"
+ encrypt = true
+ }
+}
+
+data "aws_availability_zones" "available" {}
+
+provider "aws" {
+ region = var.region
+ access_key = var.aws_access_key
+ secret_key = var.aws_secret_key
+}
+
+
+# module "vpc_instance" {
+# source = "./modules/vpc_module"
+# }
+
+# module "eks_instance" {
+# source = "./modules/eks_module"
+# }
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/rds.tf b/src/final-assessment/IaCSec/aws-infrastructure/rds.tf
new file mode 100644
index 0000000..b43ff95
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/rds.tf
@@ -0,0 +1,117 @@
+
+resource "aws_db_instance" "rds_db" {
+ count = 1
+ db_name = "tracking"
+ allocated_storage = 20
+ engine = "postgres"
+ instance_class = "db.t3.micro"
+ username = "manuel"
+ password = var.db_pwd
+ db_subnet_group_name = module.vpc.database_subnet_group_name
+ skip_final_snapshot = true //inserito solo per permettere una destroy immediata
+ vpc_security_group_ids = [aws_security_group.db_plane_sg.id]
+ deletion_protection = true
+ publicly_accessible = false
+
+ backup_retention_period = 5
+ iam_database_authentication_enabled = true
+ storage_encrypted = true
+ #tfsec:ignore:aws-rds-enable-deletion-protection
+ performance_insights_enabled = true
+ performance_insights_kms_key_id = aws_kms_key.rds_performance_insights.arn
+ performance_insights_retention_period = 7
+ multi_az = true
+ tags = {
+ LAB = "tesi_manuel"
+ infra = "terraform"
+ db_name = "rds_db"
+ }
+
+}
+
+resource "aws_kms_key" "rds_performance_insights" {
+ enable_key_rotation = true
+ deletion_window_in_days = 7
+ policy = data.aws_iam_policy_document.insight.json
+}
+
+data "aws_iam_policy_document" "insight" {
+ policy_id = "key-policy-insight"
+ statement {
+ sid = "Enable IAM User Permissions"
+ actions = [
+ "kms:*",
+ ]
+ effect = "Allow"
+ principals {
+ type = "AWS"
+ identifiers = [
+ format(
+ "arn:%s:iam::%s:root",
+ data.aws_partition.current.partition,
+ data.aws_caller_identity.current.account_id
+ )
+ ]
+ }
+ resources = ["*"]
+ }
+ statement {
+ sid = "Allow viewing RDS Performance Insights"
+ actions = [
+ "kms:Decrypt",
+ "kms:GenerateDataKey"
+ ]
+ effect = "Allow"
+ principals {
+ type = "AWS"
+ identifiers = [
+ format(
+ "arn:aws:iam::%s:user/ma.colotti@reply.it",
+ data.aws_caller_identity.current.account_id
+ )
+ ]
+ }
+ resources = ["*"]
+ condition {
+ test = "StringEquals"
+ variable = "kms:ViaService"
+ values = ["rds.${data.aws_region.current.name}.amazonaws.com"]
+ }
+ condition {
+ test = "ForAnyValue:StringEquals"
+ variable = "kms:EncryptionContext:aws:pi:service"
+ values = ["rds"]
+ }
+ condition {
+ test = "ForAnyValue:StringEquals"
+ variable = "kms:EncryptionContext:service"
+ values = ["pi"]
+ }
+ }
+}
+
+resource "aws_security_group" "db_plane_sg" {
+ name = "db-plane-sg"
+ vpc_id = module.vpc.vpc_id
+ description = "Security group for dbs"
+
+ tags = {
+ Name = "db-plane-sg"
+ LAB = "tesi_manuel"
+ infra = "terraform"
+ }
+}
+
+resource "aws_security_group_rule" "node_ingress" {
+ description = "DB ingress rule"
+ type = "ingress"
+ security_group_id = aws_security_group.db_plane_sg.id
+ from_port = 5432
+ to_port = 5432
+ protocol = "tcp"
+ source_security_group_id = module.eks.node_security_group_id
+}
+
+output "endpoint" {
+ value = aws_db_instance.rds_db[0].address
+}
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/setenv.ps1 b/src/final-assessment/IaCSec/aws-infrastructure/setenv.ps1
new file mode 100644
index 0000000..e69de29
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/sysdig-eks-agent/sysdig-eks-agent.sh b/src/final-assessment/IaCSec/aws-infrastructure/sysdig-eks-agent/sysdig-eks-agent.sh
new file mode 100644
index 0000000..70e2aed
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/sysdig-eks-agent/sysdig-eks-agent.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+helm repo add sysdig https://charts.sysdig.com
+helm repo update
+helm install sysdig-agent --namespace sysdig-agent --create-namespace \
+ --set global.sysdig.accessKey=41446d91-a0b9-4930-abbb-e2dc391ca564 \
+ --set global.sysdig.region=eu1 \
+ --set nodeAnalyzer.secure.vulnerabilityManagement.newEngineOnly=true \
+ --set global.kspm.deploy=true \
+ --set nodeAnalyzer.nodeAnalyzer.benchmarkRunner.deploy=false \
+ --set global.clusterConfig.name=eks-lab-cluster-module \
+ sysdig/sysdig-deploy
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/variables.tf b/src/final-assessment/IaCSec/aws-infrastructure/variables.tf
new file mode 100644
index 0000000..ddeaf7a
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/variables.tf
@@ -0,0 +1,45 @@
+variable "aws_access_key" {}
+variable "aws_secret_key" {}
+variable "backend_access_key" {}
+variable "backend_secret_key" {}
+
+variable "region" {
+ type = string
+ default = "eu-west-3"
+}
+
+variable "vpc_name" {
+ type = string
+ default = "eks-lab-vpc-module"
+}
+
+variable "eks_cluster_name" {
+ type = string
+ default = "eks-lab-cluster-module"
+}
+
+variable "private_subnets_num" {
+ type = number
+ default = 1
+}
+
+variable "public_subnets_num" {
+ type = number
+ default = 2
+}
+
+variable "db_subnets_num" {
+ type = number
+ default = 2
+}
+
+
+variable "cidr_block" {
+ type = string
+ default = "10.0.0.0/16"
+}
+
+variable "db_pwd" {
+ type = string
+ sensitive = true
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/aws-infrastructure/vpc_module.tf b/src/final-assessment/IaCSec/aws-infrastructure/vpc_module.tf
new file mode 100644
index 0000000..3b27f55
--- /dev/null
+++ b/src/final-assessment/IaCSec/aws-infrastructure/vpc_module.tf
@@ -0,0 +1,205 @@
+#tfsec:ignore:aws-ec2-require-vpc-flow-logs-for-all-vpcs
+
+# public subnet
+# internet gateway
+# comms between public and private
+module "vpc" {
+ source = "registry.terraform.io/terraform-aws-modules/vpc/aws"
+ version = "3.18.1"
+
+ cidr = var.cidr_block
+ azs = data.aws_availability_zones.avzs.names
+ enable_dns_hostnames = true
+
+ private_subnets = [for i in range(var.private_subnets_num) : cidrsubnet(var.cidr_block, 8, i)]
+ private_subnet_names = [for i in range(var.private_subnets_num) : "private-subnet-${i}"]
+
+
+ public_subnets = [for i in range(var.public_subnets_num) : cidrsubnet(var.cidr_block, 8, i+1)]
+ public_subnet_names = [for i in range(var.public_subnets_num) : "public-subnet-${i}"]
+ private_subnet_tags = {
+ "kubernetes.io/cluster/${var.eks_cluster_name}" = "owned"
+ }
+
+ database_subnets = [for i in range(var.db_subnets_num) : cidrsubnet(var.cidr_block, 8, var.private_subnets_num + var.public_subnets_num + i)]
+ database_subnet_names = [for i in range(var.db_subnets_num) : "db-subnet-${i}"]
+ database_subnet_group_name = "rds-db"
+
+ manage_default_security_group = true
+ default_security_group_egress = []
+ default_security_group_ingress = []
+ default_security_group_name = "${var.vpc_name}-default-sg"
+ // regula e tfsec beccano un falso positivo riguradante il flowlog durante lo scan
+
+
+ map_public_ip_on_launch = true
+
+ enable_flow_log = true
+ create_flow_log_cloudwatch_log_group = true
+ create_flow_log_cloudwatch_iam_role = true
+
+ flow_log_cloudwatch_log_group_name_prefix = "/aws/${var.vpc_name}-logz/"
+ flow_log_cloudwatch_log_group_name_suffix = "test"
+ flow_log_cloudwatch_log_group_kms_key_id = aws_kms_key.vpc_key.arn
+
+ vpc_tags = {
+ Name = var.vpc_name
+ "kubernetes.io/cluster/${var.eks_cluster_name}" = "owned"
+ }
+
+ tags = {
+ LAB = "tesi_manuel"
+ infra = "terraform"
+ }
+}
+
+resource "aws_kms_key" "vpc_key" {
+ enable_key_rotation = true
+ deletion_window_in_days = 7
+ policy = data.aws_iam_policy_document.cloudwatch.json
+}
+
+data "aws_caller_identity" "current" {}
+
+data "aws_partition" "current" {}
+
+data "aws_region" "current" {}
+
+data "aws_iam_policy_document" "cloudwatch" {
+ policy_id = "key-policy-cloudwatch"
+ statement {
+ sid = "Enable IAM User Permissions"
+ actions = [
+ "kms:*",
+ ]
+ effect = "Allow"
+ principals {
+ type = "AWS"
+ identifiers = [
+ format(
+ "arn:%s:iam::%s:root",
+ data.aws_partition.current.partition,
+ data.aws_caller_identity.current.account_id
+ )
+ ]
+ }
+ resources = ["*"]
+ }
+ statement {
+ sid = "AllowCloudWatchLogs"
+ actions = [
+ "kms:Encrypt*",
+ "kms:Decrypt*",
+ "kms:ReEncrypt*",
+ "kms:GenerateDataKey*",
+ "kms:Describe*"
+ ]
+ effect = "Allow"
+ principals {
+ type = "Service"
+ identifiers = [
+ format(
+ "logs.%s.amazonaws.com",
+ data.aws_region.current.name
+ )
+ ]
+ }
+ resources = ["*"]
+ }
+}
+
+
+
+module "vpc_vpc-endpoints" {
+ source = "registry.terraform.io/terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
+ version = "3.18.1"
+
+ vpc_id = module.vpc.vpc_id
+ security_group_ids = [aws_security_group.endpoints.id]
+ //subnet_ids = module.vpc.public_subnets
+
+ endpoints = {
+ s3 = {
+ service = "s3"
+ route_table_ids = module.vpc.private_route_table_ids
+ service_type = "Gateway"
+ tags = { Name = "s3" }
+ subnet_ids = module.vpc.public_subnets
+ },
+ ec2 = {
+ service = "ec2"
+ private_dns_enabled = true
+ tags = { Name = "ec2" }
+ subnet_ids = module.vpc.private_subnets
+ },
+ sts = {
+ service = "sts"
+ private_dns_enabled = true
+ tags = { Name = "sts" }
+ subnet_ids = module.vpc.public_subnets
+ },
+ ecr_api = {
+ service = "ecr.api"
+ private_dns_enabled = true
+ tags = { Name = "ecr_api" }
+ subnet_ids = module.vpc.public_subnets
+ },
+ ecr_dkr = {
+ service = "ecr.dkr"
+ private_dns_enabled = true
+ tags = { Name = "ecr_dkr" }
+ subnet_ids = module.vpc.public_subnets
+ },
+ ssmmessages = {
+ service = "ssmmessages"
+ private_dns_enabled = true
+ tags = { Name = "ssmmessages" }
+ subnet_ids = module.vpc.public_subnets
+ },
+ ec2messages = {
+ service = "ec2messages"
+ private_dns_enabled = true
+ tags = { Name = "ec2messages" }
+ subnet_ids = module.vpc.public_subnets
+ },
+ ssm = {
+ service = "ssm"
+ private_dns_enabled = true
+ tags = { Name = "ssm" }
+ subnet_ids = module.vpc.public_subnets
+ },
+ cloudwatch = {
+ service = "logs"
+ private_dns_enabled = true
+ tags = { Name = "logs" }
+ subnet_ids = module.vpc.public_subnets
+ }
+ }
+
+ tags = {
+ LAB = "tesi_manuel"
+ infra = "terraform"
+ }
+}
+
+resource "aws_security_group" "endpoints" {
+ name = "endpoints-ingress"
+ vpc_id = module.vpc.vpc_id
+ description = "Security group for interface endpoints"
+
+ tags = {
+ Name = "endpoints-ingress"
+ LAB = "tesi_manuel"
+ infra = "terraform"
+ }
+}
+
+resource "aws_security_group_rule" "endpoint-ingress" {
+ description = "Endpoint ingress rule"
+ type = "ingress"
+ security_group_id = aws_security_group.endpoints.id
+ from_port = 1025
+ to_port = 65535
+ protocol = -1
+ source_security_group_id = module.eks.node_security_group_id
+}
diff --git a/src/final-assessment/IaCSec/iacsec-assessment.md b/src/final-assessment/IaCSec/iacsec-assessment.md
new file mode 100644
index 0000000..27bf1f1
--- /dev/null
+++ b/src/final-assessment/IaCSec/iacsec-assessment.md
@@ -0,0 +1,64 @@
+# IaC Security Assessment
+Total (Checkov) = 341
+
+## Components included:
+- AWS infrastructure (Terraform)
+- Azure Observability (Terraform)
+- HCP Vault on VM (Terraform)
+- Azure MySQL Database (Terraform)
+- Keycloak (Terraform)
+- Kubernetes (YAML)
+
+## Main Vulnerabilities - Checkov
+- Ensure Azure Kubernetes Cluster (AKS) nodes should use a minimum number of 50 pods. CKV_AZURE_168 (max_pods parameter in aks node_pool)
+- Ensure AKS local admin account is disabled. CKV_AZURE_141 (local_account_disabled = true in aks)
+- Ensure AKS API server defines authorized IP ranges. CKV_AZURE_6 (api_server_authorized_ip_ranges = "0.0.0.0/0")
+- Ensure AKS enables private clusters. CKV_AZURE_115 (private_cluster_enabled = true)
+- Ensure that Azure Key Vault disables public network access. CKV_AZURE_189 (network_acls in Vault-On-VM Azure Key Vault, public_network_access_enabled = false)
+- Ensure that key vault enables purge protection. CKV_AZURE_110 (purge_protection_enabled = true)
+- Ensure the key vault is recoverable CKV_AZURE_42 (soft_delete_retention_days = 7)
+- Ensure that key vault key is backed by HSM CKV_AZURE_112 (key_type = "RSA-HSM")
+- Ensure all keys have an expiration date. CKV_AZURE_40 (expiration_date = "2020-12-30T20:00:00Z")
+- Ensure that SSH access is restricted from the internet CKV_AZURE_10 (commented Inbound SSH rule in Netwok Security Group (main.tf of Vault))
+- Ensure that Storage blobs restrict public access CKV_AZURE_190 (public_network_access_enabled = false)
+- Ensure that AWS database instances have deletion protection enabled CKV_AWS_293 (deletion_protection = true)
+- Minimize the admission of pods which lack an associated NetworkPolicy CKV_K8S_6
+- Minimize the admission of containers with capabilities assigned CKV_K8S_37 (security context capabilities)
+- Containers should run as a high UID to avoid host conflict CKV_K8S_40 (security context runAsUser)
+- Containers should not run with allowPrivilegeEscalation CKV_K8S_20 (allowPrivilegeEscalation=false)
+- Ensure that the seccomp profile is set to docker/default or runtime/default CKV_K8S_31 (seccomp_profile RuntimeDefault)
+- Ensure FTP deployments are disabled CKV_AZURE_78 (ftps_state)
+
+
+
+Search filter: pr:38 tool:checkov is:open sort:created-desc path:/src/final-assessment
+
+
+
+## Main Vulnerabilities - Sysdig App
+- 5 High
+- 37 Medium
+- 37 Low
+
+
+### HIGH
+- Container allowing privileged sub processes | 🔴 High | 1 Occurrences (SOLVED AFTER CHECKOV)
+- Container with NET_RAW capability | 🔴 High | 1 Occurrences (SOLVED AFTER CHECKOV)
+- Container with RunAsUser root or not set | 🔴 High | 1 Occurrences (SOLVED AFTER CHECKOV)
+- Container with writable root file system | 🔴 High | 1 Occurrences (SOLVED AFTER CHECKOV)
+- RDS - Instance Not Public Accessible | 🔴 High | 1 Occurrences (SOLVED publicly_accessible = false)
+
+### MEDIUM
+- Container using image without digest | 🟠Medium | 13 Occurrences (DETECTED BY CHECKOV TOO, NEGLIGIBLE)
+- Container using latest image | 🟠Medium | 2 Occurrences (DETECTED BY CHECKOV TOO, NEGLIGIBLE)
+- Container with ANY capability | 🟠Medium | 1 Occurrences (SOLVED, bad formatting of securityContext capability)
+- Container with root group access | 🟠Medium | 1 Occurrences (Solved with runAsGroup capability)
+- KMS - Enabled CMKs Rotation | 🟠Medium | 2 Occurrences (NEGLECTED)
+- Policies - Defined Containers Security Context | 🟠Medium | 1 Occurrences (SOLVED BY CHECKOV)
+- Workload container default RunAsGroup root | 🟠Medium | 1 Occurrences (Solved with runAsGroup capability)
+- Workload missing CPU limit | 🟠Medium | 2 Occurrences (NEGLECTED)
+- Workload missing memory limit | 🟠Medium | 2 Occurrences (NEGLECTED)
+- Workload using "default" ServiceAccount | 🟠Medium | 11 Occurrences (DETECTED BY CHECKOV TOO, NEGLIGIBLE)
+- Workload with writable volumes | 🟠Medium | 1 Occurrences (NEGLECTED)
+
+## Run time of pipelines
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/keycloak_webapp/.terraform.lock.hcl b/src/final-assessment/IaCSec/keycloak_webapp/.terraform.lock.hcl
new file mode 100644
index 0000000..8042219
--- /dev/null
+++ b/src/final-assessment/IaCSec/keycloak_webapp/.terraform.lock.hcl
@@ -0,0 +1,42 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/azure/azapi" {
+ version = "1.6.0"
+ constraints = "1.6.0"
+ hashes = [
+ "h1:811BWhYipddBITHXvIIAr20JcKkl27P/Vve8ewyUecw=",
+ "zh:0784acbac6d911f31176713bcfb5e3a4a8085cff8f55283a37b0d8e784b2ea79",
+ "zh:3ff0ddb2b0dfff4037eb8da856b0ba7bfb1328004bee638028c17ef28326bfdc",
+ "zh:5de832e66c2582063c5d29c2c4916deddbcbf7f7c277b60d30e3292f487f7064",
+ "zh:61f7b11d51508cb3c988cc2d846b8edb88f5461b5a6ff3a6539c6131999c4bf8",
+ "zh:7c267b474d26dd0f6e1b9674250cc3c66b7e5a31d26cd4f2138154260712d000",
+ "zh:830aef5fb62085652a151d8a593b6d60ce7e87f2526661840ecd147a5ca13e23",
+ "zh:885236c0921e6ee20e5c3aa2a82e90fef74873f094a9c27c3ddc688ec5a83e94",
+ "zh:93feb60ab4781a01a54ef6983781ae76e60908ffeb1037f2702146542b235ddc",
+ "zh:966cbb563b7aa8180d6f0ac029eb6cc6a4261a6e4dc7d7662f270d99066abcec",
+ "zh:a1974c3ee0fb9d6b6318985460c21c7bd439eff157f318b74570f725f0a537b1",
+ "zh:d2a3284c4546804b84913237dbdb31966be733eb5199699df5af25b69e11e012",
+ "zh:f83a023655e4385a6e4733c724c17eb262fcc06ad2a198ccb879c92ca50dcb2e",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.52.0"
+ constraints = "3.52.0"
+ hashes = [
+ "h1:atlTwMcGXXF0rKzLNZhKj7djwoKT4b6in+xa2Hz09Y8=",
+ "zh:0c3029da7454f2fe7058939d95c458d9930842f06430cfcd0713713f3d788216",
+ "zh:826584f11eaaec7f179e85d9cc4833ec7a1d854ed4883c94317427ddfa7ffd11",
+ "zh:8fff204176ee1b08d168848d4bd7a051d7fd189688ca8b5f26eb31855ea060a6",
+ "zh:a170ebe199b93ea1f20357d848dfd0f5e50538236f09939d1a11a61dfbfded0f",
+ "zh:acea54d715186101f8a7725997578b231e4db50eea0fb9f9868ecd867008e6e6",
+ "zh:ae0f6a61677282a2f605ca9d0a74a08ae78ae2efeb372a33b9d4c7210fbbfd2c",
+ "zh:c2c2329f3864e10ee15993c1a48e79bf72d570bb6d08003038a37b73e551dbf9",
+ "zh:c7a4a117628ff0ad24e9c73f1087e9a02b8eca633b0913ee1687b0b4b5c7f377",
+ "zh:e1a290e708e7dbbde8747a98680f7a1aace97694a243ba7a11cc5c77e982e9cc",
+ "zh:e82aa1c5e8ead3087968d7f44b6f644ef3092a0d243b4b575ff8847616e290b3",
+ "zh:f4d57d3c5f3c7fe064b88151036037b7852be6bcfa661e3f4fe0fda2871006d9",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
diff --git a/src/final-assessment/IaCSec/keycloak_webapp/keycloak.tf b/src/final-assessment/IaCSec/keycloak_webapp/keycloak.tf
new file mode 100644
index 0000000..5d1e630
--- /dev/null
+++ b/src/final-assessment/IaCSec/keycloak_webapp/keycloak.tf
@@ -0,0 +1,56 @@
+
+resource "azurerm_service_plan" "keycloak-sp" {
+ name = "keycloak-sp"
+ resource_group_name = var.keycloak-resource-group.name
+ location = var.keycloak-resource-group.location
+ os_type = "Linux"
+ sku_name = "F1"
+
+ depends_on = [ azurerm_resource_group.keycloak-resource-group ]
+}
+
+resource "azurerm_linux_web_app" "keycloak-webapp" {
+ name = "keycloak-iam-webapp"
+ resource_group_name = var.keycloak-resource-group.name
+ location = var.keycloak-resource-group.location
+ service_plan_id = azurerm_service_plan.keycloak-sp.id
+
+ https_only = true
+
+ app_settings = {
+ "KEYCLOAK_USER" = "admin"
+ "KEYCLOAK_PASSWORD" = sensitive(var.secrets.admin_password)
+ "DOCKER_REGISTRY_SERVER_URL" = "https://registry.hub.docker.com/v2/"
+ "WEBSITE_ENABLE_APP_SERVICE_STORAGE" = true
+ "FRONTEND_URL" = "https://keycloak-iam-webapp.azurewebsites.net/auth"
+ }
+
+ site_config {
+ always_on = false
+ ftps_state = "FtpsOnly"
+ }
+
+ depends_on = [ azurerm_service_plan.keycloak-sp ]
+
+}
+
+output "hostname" {
+ value = azurerm_linux_web_app.keycloak-webapp.default_hostname
+}
+
+resource "azapi_update_resource" "update_linux_web_app" {
+ resource_id = azurerm_linux_web_app.keycloak-webapp.id
+ type = "Microsoft.Web/sites@2022-03-01"
+ body = jsonencode({
+ properties = {
+ "siteConfig" = {
+ "linuxFxVersion" = "COMPOSE|${base64encode(file("keycloak_service.yaml"))}"
+ }
+ "appSettings" = {
+ "keycloakFrontendUrl" = join("/", [azurerm_linux_web_app.keycloak-webapp.default_hostname, "auth"])
+ }
+ }
+ })
+
+ depends_on = [ azurerm_linux_web_app.keycloak-webapp ]
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/keycloak_webapp/keycloak_service.yaml b/src/final-assessment/IaCSec/keycloak_webapp/keycloak_service.yaml
new file mode 100644
index 0000000..3c9987f
--- /dev/null
+++ b/src/final-assessment/IaCSec/keycloak_webapp/keycloak_service.yaml
@@ -0,0 +1,11 @@
+version: '3'
+
+services:
+ keycloak:
+ image: jboss/keycloak:latest
+ container_name: keycloak
+ environment:
+ - PROXY_ADDRESS_FORWARDING=true
+ volumes:
+ - ${WEBAPP_STORAGE_HOME}/data:/opt/jboss/keycloak/standalone/data
+ restart: always
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/keycloak_webapp/main.tf b/src/final-assessment/IaCSec/keycloak_webapp/main.tf
new file mode 100644
index 0000000..d3c179a
--- /dev/null
+++ b/src/final-assessment/IaCSec/keycloak_webapp/main.tf
@@ -0,0 +1,39 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "3.52.0"
+ }
+
+ azapi = {
+ source = "azure/azapi"
+ version = "1.6.0"
+ }
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform-rg"
+ storage_account_name = "terraformbackendmanuel"
+ container_name = "tfstate"
+ key = "terraform.tfstate_keycloak_app"
+ }
+}
+
+provider "azapi" {
+
+}
+
+
+provider "azurerm" {
+ subscription_id = var.credentials["subscription_id"]
+ client_id = var.credentials["client_id"]
+ client_secret = var.azure_sp_key
+ tenant_id = var.credentials["tenant_id"]
+ features {}
+}
+
+
+resource "azurerm_resource_group" "keycloak-resource-group" {
+ name = var.keycloak-resource-group.name
+ location = var.keycloak-resource-group.location
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/keycloak_webapp/variables.tf b/src/final-assessment/IaCSec/keycloak_webapp/variables.tf
new file mode 100644
index 0000000..c435f2a
--- /dev/null
+++ b/src/final-assessment/IaCSec/keycloak_webapp/variables.tf
@@ -0,0 +1,33 @@
+variable "azure_sp_key" {}
+
+variable "credentials" {
+ description = "Azure Service Provider Credentials"
+ type = map(string)
+ default = {
+ subscription_id = "945fc713-dc5d-4ba6-9b6b-2f1fb2225b19"
+ tenant_id = "c5179d57-9fa0-4d70-bf82-c3e49fc377d9"
+ client_id = "8267d52d-29b9-4a06-ac44-1c6743c8b010"
+ }
+}
+
+# Politecnico Account
+# subscription_id: "8eb30f69-69f6-4ff0-99ea-f9edd2274036"
+# tenant_id: "2a05ac92-2049-4a26-9b34-897763efc8e2"
+# client_id: "12d6c386-4977-4aea-9b56-902c514c9d14"
+
+
+# Reply Account
+# subscription id: 945fc713-dc5d-4ba6-9b6b-2f1fb2225b19
+# tenant id: c5179d57-9fa0-4d70-bf82-c3e49fc377d9
+# client id: 8267d52d-29b9-4a06-ac44-1c6743c8b010
+
+
+
+variable "keycloak-resource-group" {
+ description = "Azure AKS Resource Group Info"
+ type = map(string)
+ default = {
+ name = "keycloak-resource-group"
+ location = "francecentral"
+ }
+}
\ No newline at end of file
diff --git a/src/final-assessment/IaCSec/mysql_database/main.tf b/src/final-assessment/IaCSec/mysql_database/main.tf
new file mode 100644
index 0000000..e05f0e4
--- /dev/null
+++ b/src/final-assessment/IaCSec/mysql_database/main.tf
@@ -0,0 +1,36 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "3.52.0"
+ }
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform"
+ storage_account_name = "terraformstate1603709092"
+ container_name = "tfstate"
+ key = "terraform.tfstate_mysql_db"
+ }
+}
+
+
+provider "azurerm" {
+ subscription_id = var.credentials["subscription_id"]
+ client_id = var.credentials["client_id"]
+ client_secret = var.azure_sp_key
+ tenant_id = var.credentials["tenant_id"]
+ features {}
+}
+
+
+resource "azurerm_resource_group" "mysql_db_resource_group" {
+ name = var.mysql_db_resource_group.name
+ location = var.mysql_db_resource_group.location
+}
+
+
+
+
+
+
diff --git a/src/final-assessment/IaCSec/mysql_database/mysql_database.tf b/src/final-assessment/IaCSec/mysql_database/mysql_database.tf
new file mode 100644
index 0000000..c07c7b3
--- /dev/null
+++ b/src/final-assessment/IaCSec/mysql_database/mysql_database.tf
@@ -0,0 +1,76 @@
+
+resource "azurerm_virtual_network" "database_virtual_network" {
+ name = "database_virtual_network"
+ location = var.mysql_db_resource_group.location
+ resource_group_name = var.mysql_db_resource_group.name
+ address_space = ["10.0.0.0/16"]
+}
+
+resource "azurerm_subnet" "database_vn_subnet" {
+ name = "database_vn_subnet"
+ resource_group_name = var.mysql_db_resource_group.name
+ virtual_network_name = var.mysql_db_resource_group.location
+ address_prefixes = ["10.0.2.0/24"]
+ service_endpoints = ["Microsoft.Storage"]
+ delegation {
+ name = "fs"
+ service_delegation {
+ name = "Microsoft.DBforMySQL/flexibleServers"
+ actions = [
+ "Microsoft.Network/virtualNetworks/subnets/join/action",
+ ]
+ }
+ }
+}
+
+resource "azurerm_network_security_group" "db_network_nsg" {
+ name = "databaseNSG"
+ location = var.mysql_db_resource_group.location
+ resource_group_name = var.mysql_db_resource_group.name
+
+ security_rule {
+ name = "InboundDBConnections"
+ priority = 100
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "Tcp"
+ source_port_range = "*"
+ destination_port_range = "3306"
+ source_address_prefix = "*"
+ destination_address_prefix = "*"
+ }
+}
+
+resource "azurerm_subnet_network_security_group_association" "example" {
+ subnet_id = azurerm_subnet.database_vn_subnet.id
+ network_security_group_id = azurerm_network_security_group.db_network_nsg.id
+}
+
+
+
+resource "azurerm_private_dns_zone" "database_dns_zone" {
+ name = "databasemysqlmec.com"
+ resource_group_name = var.mysql_db_resource_group.name
+}
+
+resource "azurerm_private_dns_zone_virtual_network_link" "private_dns_zone" {
+ name = "exampleVnetZone.com"
+ private_dns_zone_name = azurerm_private_dns_zone.database_dns_zone.name
+ virtual_network_id = azurerm_virtual_network.database_virtual_network.id
+ resource_group_name = var.mysql_db_resource_group.name
+}
+
+resource "azurerm_mysql_flexible_server" "mysql_flexible_server" {
+ name = "databasemysqlmec"
+ resource_group_name = var.mysql_db_resource_group.name
+ location = var.mysql_db_resource_group.location
+ administrator_login = "runcor3"
+ administrator_password = "testFakePassword."
+ backup_retention_days = 7
+ delegated_subnet_id = azurerm_subnet.database_vn_subnet.id
+ private_dns_zone_id = azurerm_private_dns_zone.database_dns_zone.id
+ sku_name = "B_Standard_B1s"
+ version = "8.0.21"
+ depends_on = [azurerm_resource_group.mysql_db_resource_group,
+ azurerm_private_dns_zone_virtual_network_link.private_dns_zone]
+}
diff --git a/src/final-assessment/IaCSec/mysql_database/variables.tf b/src/final-assessment/IaCSec/mysql_database/variables.tf
new file mode 100644
index 0000000..c152184
--- /dev/null
+++ b/src/final-assessment/IaCSec/mysql_database/variables.tf
@@ -0,0 +1,24 @@
+
+variable "azure_sp_key" {}
+
+variable "credentials" {
+ description = "Azure Service Provider Credentials"
+ type = map(string)
+ default = {
+ subscription_id = "8eb30f69-69f6-4ff0-99ea-f9edd2274036"
+ tenant_id = "2a05ac92-2049-4a26-9b34-897763efc8e2"
+ client_id = "12d6c386-4977-4aea-9b56-902c514c9d14"
+ }
+}
+
+
+variable "mysql_db_resource_group" {
+ description = "Azure MySQL DB Resource Group Info"
+ type = map(string)
+ default = {
+ name = "mysql-db-resource-group"
+ location = "UK South"
+ }
+}
+
+
diff --git a/src/final-assessment/IaCSec_Resolution/NetworkPolicy_CKV2_K8S_6.yaml b/src/final-assessment/IaCSec_Resolution/NetworkPolicy_CKV2_K8S_6.yaml
new file mode 100644
index 0000000..8a33a0e
--- /dev/null
+++ b/src/final-assessment/IaCSec_Resolution/NetworkPolicy_CKV2_K8S_6.yaml
@@ -0,0 +1,83 @@
+# Mail Network Policy
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: mail-service-network-policy
+ namespace: default
+spec:
+ podSelector:
+ matchLabels:
+ role: mail-service
+ policyTypes:
+ - Ingress
+ - Egress
+ ingress:
+ - from: []
+ ports:
+ - protocol: TCP
+ port: 995
+ - protocol: TCP
+ port: 110
+ egress:
+ - to: []
+ ports:
+ - protocol: TCP
+ port: 465
+ - protocol: TCP
+ port: 25
+ - protocol: TCP
+ port: 26
+
+---
+
+# Default Network Policy
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-network-policy
+ namespace: default
+spec:
+ podSelector:
+ matchLabels:
+ role: example-pod
+ policyTypes:
+ - Ingress
+ - Egress
+ ingress:
+ - from: []
+ ports:
+ - protocol: TCP
+ port: 0
+
+ egress:
+ - to: []
+ ports:
+ - protocol: TCP
+ port: 0
+
+---
+
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-deployment-network-policy
+ namespace: default
+spec:
+ podSelector:
+ matchLabels:
+ role: default-deployment
+ policyTypes:
+ - Ingress
+ - Egress
+ ingress:
+ - from: []
+ ports:
+ - protocol: TCP
+ port: 0
+
+ egress:
+ - to: []
+ ports:
+ - protocol: TCP
+ port: 0
+
diff --git a/src/final-assessment/resources_list.md b/src/final-assessment/resources_list.md
new file mode 100644
index 0000000..bc28f91
--- /dev/null
+++ b/src/final-assessment/resources_list.md
@@ -0,0 +1,4 @@
+- Keycloak Webapp
+- Vault_K8s/Azure_Full_DB_K8s_Vault_Deployment every reflink (Mysql, K8s, Vault-on-VM)
+- Observability => Azure => Terraform_Deployment
+- Terraform-IaCSec => aws-infrastructure
\ No newline at end of file