Skip to content

Commit f6a876f

Browse files
authored
Merge pull request #2 from MicrosoftCloudEssentials-LearningHub/terraform-iac
Demonstration: Deploying Azure Resources for a Data Platform
2 parents 2a85c3c + 4280955 commit f6a876f

10 files changed

Lines changed: 545 additions & 2 deletions

README.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Costa Rica
55
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
66
[brown9804](https://github.com/brown9804)
77

8-
Last updated: 2025-02-21
8+
Last updated: 2025-04-15
99

1010
------------------------------------------
1111

@@ -27,6 +27,80 @@ Last updated: 2025-02-21
2727

2828
</details>
2929

30+
## Prerequisites
31+
32+
- An `Azure subscription is required`. All other resources, including instructions for creating a Resource Group, are provided in this workshop.
33+
- `Contributor role assigned or any custom role that allows`: access to manage all resources, and the ability to deploy resources within subscription.
34+
- If you choose to use a Terraform approach, please ensure that:
35+
- [Terraform is installed on your local machine](https://developer.hashicorp.com/terraform/tutorials/azure-get-started/install-cli#install-terraform).
36+
- [Install the Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) to work with both Terraform and Azure commands.
37+
38+
## Infrastructure as Code (IaC)
39+
40+
> Is crucial for modern cloud-based solutions and applications. Here is why:
41+
42+
<details>
43+
<summary>1. Consistency and Reproducibility</summary>
44+
45+
- **Consistent Environments**: IaC ensures that your development, testing, and production environments are consistent. `This reduces the it works on my machine problem` and ensures that applications run reliably across different environments.
46+
- **Reproducibility**: With IaC, you can `recreate your infrastructure from scratch in a consistent manner.` This is particularly useful for `disaster recovery and scaling`.
47+
48+
</details>
49+
50+
<details>
51+
<summary>2. Version Control</summary>
52+
53+
- **Source Control**: By storing IaC configurations in version control systems like GitHub, you `can track changes, collaborate with team members, and roll back to previous versions if needed.`
54+
- **Change Management**: Version control `provides a history of changes, making it easier to understand what changes were made, who made them, and why.`
55+
56+
</details>
57+
58+
<details>
59+
<summary>3. Flexibility and Options</summary>
60+
61+
62+
> Microsoft provides several IaC tools, including Terraform, Bicep, and ARM templates. Each tool offers different features and benefits, allowing you to choose the one that best fits your needs.
63+
64+
- **Terraform**: A popular IaC tool that uses a high-level configuration language to define and provision infrastructure. It `supports multiple cloud providers, making it a versatile choice.`
65+
- **Bicep**: A domain-specific language that uses declarative syntax to deploy Azure resources. It offers a `concise and easy-to-read alternative to JSON-based ARM templates.`
66+
- **ARM Templates**: JSON files that` define the infrastructure and configuration for your Azure solution.` They provide a detailed and flexible way to manage Azure resources.
67+
68+
</details>
69+
70+
<details>
71+
<summary>4. Enhanced Security</summary>
72+
73+
- **Automated Security Policies**: IaC allows you to `define and enforce security policies automatically.` This ensures that security best practices are `consistently applied across all environments.`
74+
- **Compliance**: IaC helps maintain compliance with `regulatory requirements by providing a clear and auditable trail of infrastructure changes.`
75+
76+
</details>
77+
78+
<details>
79+
<summary>5. Scalability</summary>
80+
81+
- **Dynamic Scaling**: IaC enables `dynamic scaling of resources based on demand.` This ensures that your infrastructure can handle varying workloads efficiently.
82+
- **Resource Optimization**: By automating the `provisioning and de-provisioning of resources,` IaC helps optimize resource usage and reduce costs.
83+
84+
</details>
85+
86+
<details>
87+
<summary>6. Automation</summary>
88+
89+
- **Automated Provisioning**: IaC allows you to `automate the provisioning of infrastructure. This reduces manual errors, speeds up deployments, and ensures that infrastructure changes are applied consistently.`
90+
- **CI/CD Integration**: Integrating IaC with `Continuous Integration/Continuous Deployment (CI/CD) pipelines automates the deployment process, ensuring that infrastructure changes are tested and deployed alongside application code.`
91+
92+
</details>
93+
94+
95+
> [!TIP]
96+
> Just in case, find here some [additional Terraform templates for different Azure resources across different areas](https://github.com/MicrosoftCloudEssentials-LearningHub/AzureTerraformTemplates-v0.0.0).
97+
98+
> E.g [Demonstration: Deploying Azure Resources for a Data Platform](./Terraform)
99+
100+
<div align="center">
101+
<img src="https://github.com/user-attachments/assets/16640052-7f57-443a-9efd-30855de5e231" alt="Centered Image" style="border: 2px solid #4CAF50; border-radius: 5px; padding: 5px;"/>
102+
</div>
103+
30104

31105
<div align="center">
32106
<h3 style="color: #4CAF50;">Total Visitors</h3>

Terraform/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Costa Rica
55
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
66
[brown9804](https://github.com/brown9804)
77

8-
Last updated: 2025-03-13
8+
Last updated: 2025-04-15
99

1010
------------------------------------------
1111

@@ -34,6 +34,7 @@ Last updated: 2025-03-13
3434

3535
- [Overview](#overview)
3636
- [Finding admin_principal_id Using Azure CLI](#finding-admin_principal_id-using-azure-cli)
37+
- [Configure Remote Storage for a Terraform deployment](#configure-remote-storage-for-a-terraform-deployment)
3738
- [How to execute it](#how-to-execute-it)
3839

3940
</details>
@@ -78,6 +79,16 @@ Here is an example value for `admin_principal_id` which is Object ID you retriev
7879
admin_principal_id = "12345678-1234-1234-1234-1234567890ab"
7980
```
8081

82+
## Configure Remote Storage for a Terraform deployment
83+
84+
> To configure remote storage for a Terraform deployment, you need to set up a backend configuration in your Terraform files. This backend configuration specifies where Terraform should store the state file, which keeps track of the resources it manages.
85+
86+
> 1. Create an Azure Storage Account: <br/>
87+
> - Go to the Azure portal and create a new storage account (if you don't have one already). <br/>
88+
> - Note down the storage account name and the access key. <br/>
89+
> 2. Create a Storage Container: Within the storage account, create a new container to store the Terraform state file.
90+
> 3. Configure Terraform Backend: In your Terraform configuration file (e.g., [remote-storage.tf](./src/remote-storage.tf), add the backend configuration for Azure Blob Storage.
91+
8192
## How to execute it
8293

8394
```mermaid
File renamed without changes.

Terraform/src/main.tf

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Retrieve the client configuration of the AzureRM provider
2+
data "azurerm_client_config" "example" {}
3+
4+
# Check the directory object type
5+
data "azuread_directory_object" "example" {
6+
object_id = data.azurerm_client_config.example.object_id
7+
}
8+
9+
# Get information about the Entra user
10+
data "azuread_user" "example" {
11+
object_id = data.azurerm_client_config.example.object_id
12+
}
13+
14+
# Local value to determine if the client is a user or not
15+
locals {
16+
fabric_admin = can(data.azuread_directory_object.example.type == "User") ? data.azuread_user.example.user_principal_name : data.azurerm_client_config.example.object_id
17+
}
18+
19+
# Create a resource group
20+
resource "azurerm_resource_group" "example" {
21+
name = var.resource_group_name # Name of the resource group
22+
location = var.location # Location of the resource group
23+
}
24+
25+
# Create a storage account for remote state
26+
resource "azurerm_storage_account" "example" {
27+
name = var.storage_account_name
28+
resource_group_name = azurerm_resource_group.example.name
29+
location = azurerm_resource_group.example.location
30+
account_tier = "Standard"
31+
account_replication_type = "LRS"
32+
depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
33+
}
34+
35+
# Create a storage container for remote state
36+
resource "azurerm_storage_container" "example" {
37+
name = var.container_name
38+
storage_account_name = azurerm_storage_account.example.name
39+
container_access_type = "private"
40+
depends_on = [azurerm_storage_account.example] # Ensure storage account is created first
41+
}
42+
43+
# Create an MSSQL Server
44+
resource "azurerm_mssql_server" "example" {
45+
name = var.sql_server_name # Name of the SQL Server
46+
resource_group_name = azurerm_resource_group.example.name # Resource group name
47+
location = azurerm_resource_group.example.location # Location of the SQL Server
48+
version = "12.0" # SQL Server version
49+
administrator_login = var.admin_username # Administrator username
50+
administrator_login_password = var.admin_password # Administrator password
51+
depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
52+
}
53+
54+
# Add a null resource to introduce a delay
55+
resource "null_resource" "wait_for_sql_server" {
56+
depends_on = [azurerm_mssql_server.example]
57+
58+
provisioner "local-exec" {
59+
command = "Start-Sleep -Seconds 60"
60+
interpreter = ["PowerShell", "-Command"]
61+
}
62+
}
63+
64+
# Create an MSSQL Database
65+
resource "azurerm_mssql_database" "example" {
66+
name = var.sql_database_name # Name of the SQL Database
67+
server_id = azurerm_mssql_server.example.id # ID of the SQL Server
68+
sku_name = "Basic" # SKU name for the SQL Database
69+
depends_on = [null_resource.wait_for_sql_server] # Ensure SQL Server is fully provisioned first
70+
}
71+
72+
# Create Microsoft Fabric Capacity
73+
resource "azurerm_fabric_capacity" "example" {
74+
name = "fc${var.solution_name}"
75+
resource_group_name = azurerm_resource_group.example.name
76+
location = var.location
77+
78+
administration_members = setunion([local.fabric_admin], var.fabric_capacity_admin_upns)
79+
80+
sku {
81+
name = var.fabric_capacity_sku
82+
tier = "Fabric"
83+
}
84+
depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
85+
}
86+
87+
# Get the Fabric Capacity details
88+
data "fabric_capacity" "example" {
89+
display_name = azurerm_fabric_capacity.example.name
90+
91+
lifecycle {
92+
postcondition {
93+
condition = self.state == "Active"
94+
error_message = "Fabric Capacity is not in Active state. Please check the Fabric Capacity status."
95+
}
96+
}
97+
}
98+
99+
# Create a Fabric Workspace
100+
resource "fabric_workspace" "example" {
101+
capacity_id = data.fabric_capacity.example.id
102+
display_name = "ws-${var.solution_name}"
103+
depends_on = [data.fabric_capacity.example] # Ensure Fabric Capacity data source is available first
104+
}

Terraform/src/outputs.tf

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Output the name of the resource group
2+
output "resource_group_name" {
3+
value = azurerm_resource_group.example.name # The name of the resource group
4+
}
5+
6+
# Output the name of the storage account
7+
output "storage_account_name" {
8+
value = azurerm_storage_account.example.name # The name of the storage account
9+
}
10+
11+
# Output the name of the storage container
12+
output "storage_container_name" {
13+
value = azurerm_storage_container.example.name # The name of the storage container
14+
}
15+
16+
# Output the name of the MSSQL Server
17+
output "sql_server_name" {
18+
value = azurerm_mssql_server.example.name # The name of the SQL Server
19+
}
20+
21+
# Output the name of the MSSQL Database
22+
output "sql_database_name" {
23+
value = azurerm_mssql_database.example.name # The name of the SQL Database
24+
}
25+
26+
# Output the name of the Microsoft Fabric Capacity
27+
output "fabric_capacity_name" {
28+
value = azurerm_fabric_capacity.example.name
29+
}
30+
31+
output "fabric_workspace_name" {
32+
value = fabric_workspace.example.display_name
33+
}

Terraform/src/provider.tf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
terraform {
2+
required_version = ">= 1.8, < 2.0"
3+
# Specify the required providers and their versions
4+
required_providers {
5+
azurerm = {
6+
source = "hashicorp/azurerm" # Source of the AzureRM provider
7+
version = "~> 4.16.0" # Version of the AzureRM provider
8+
}
9+
fabric = {
10+
source = "microsoft/fabric"
11+
version = "0.1.0-beta.7"
12+
}
13+
}
14+
}
15+
16+
provider "azurerm" {
17+
features {} # Enable all features for the AzureRM provider
18+
subscription_id = var.subscription_id # Add your subscription ID here
19+
}
20+
21+
provider "fabric" {}

Terraform/src/remote-storage.tf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
terraform {
2+
backend "azurerm" {
3+
resource_group_name = "RGWorkshopUserName" # The name of the resource group for remote state storage
4+
storage_account_name = "examplestorageacctworkshop" # The name of the storage account for remote state storage
5+
container_name = "tfstate" # The name of the container for remote state storage
6+
key = "terraform.tfstate" # The key for the remote state file
7+
}
8+
}

Terraform/src/terraform.tfvars

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# ----------------------------------
2+
### Here is some sample data. Please make any necessary modifications. 
3+
# ----------------------------------
4+
5+
# Variable for subscription ID
6+
subscription_id = "" # Add your subscription id number
7+
8+
# Resource group name
9+
resource_group_name = "" # Add your desired RG name
10+
11+
# Location of the resources
12+
location = "Central US"
13+
14+
# SQL Server configuration
15+
sql_server_name = "usernamesqlserver" # replace username with your name
16+
admin_username = "adminuser" # replace with your desired user name
17+
admin_password = "P@ssw0rd1234" # Make sure to use a strong password
18+
19+
# SQL Database name
20+
sql_database_name = "workshopdbusername" # replace username with your name
21+
22+
# Variables for remote state storage
23+
storage_account_name = "storageacctworkshop01"
24+
container_name = "tfstate"
25+
26+
# Variable for administrator principal ID
27+
admin_principal_id = ""
28+
29+
# Microsoft Fabric Capacity configuration
30+
solution_name = "capacitynamews" # choose your capacity name
31+
fabric_capacity_admin_upns = ["user-email-here", "another-user-email-here"]
32+
fabric_capacity_sku = "F64" # Choose your SKU like F64

0 commit comments

Comments
 (0)