Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e6b3654
arch
brown9804 Apr 15, 2025
5d0758e
Merge e6b36546708616df51c5aa7595425a71444d24fc into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
8ea840e
+ troubleshooting.md
brown9804 Apr 15, 2025
1d0a8df
Merge 8ea840e4bd2e86aa97776a1ee6e08d15b9bde97c into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
03d24a8
Update last modified date in Markdown files
github-actions[bot] Apr 15, 2025
a3cef84
moved
brown9804 Apr 15, 2025
6e970d7
Merge a3cef8455ca40d46791bcbb1056533b589f4ee1c into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
194407c
+ variables.tf
brown9804 Apr 15, 2025
94a7817
Merge 194407cc61e88a2e8b8e068dffa561e65e8d7888 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
2e13d33
+ terraform.tfvars
brown9804 Apr 15, 2025
5b92f6e
Merge 2e13d333b4c72b0f96f6f7c1acf221a142afff06 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
a9ddb69
+ provider.tf
brown9804 Apr 15, 2025
5107627
Merge a9ddb693b7c0f28301b7108db2d2225a6c75db19 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
a3e301a
+ outputs.tf
brown9804 Apr 15, 2025
12141bd
Merge a3e301adb7a30525128927700788f71e25fd5ee2 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
f84ccb4
+ main.tf
brown9804 Apr 15, 2025
207a7d7
Merge f84ccb4e55928478ec094851cda98288ca8e4bcb into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
cb9ef00
+remote-storage.tf
brown9804 Apr 15, 2025
7caa51b
Merge cb9ef001662872c98198b7ff27e3fe0c5992a2c1 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
34653b9
Configure Remote Storage for a Terraform deployment
brown9804 Apr 15, 2025
857e1c3
Merge 34653b92b29282c07150c18ae0aa6d3ce96edcf7 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
e33eec1
Update last modified date in Markdown files
github-actions[bot] Apr 15, 2025
7b348ad
+ pre requesites
brown9804 Apr 15, 2025
4e11ab1
Merge 7b348ad05c4a757516b39d47b789411d68046f28 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
d23c579
Update last modified date in Markdown files
github-actions[bot] Apr 15, 2025
d1b237d
format
brown9804 Apr 15, 2025
deb56aa
Merge d1b237dea9d74c6cf66073bd04bcfcfcb38af45e into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
8bf6142
+ Infrastructure as Code (IaC)
brown9804 Apr 15, 2025
7c79826
Merge 8bf6142a5fb13472730261ca89c7b632d79af994 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
fdaa551
iac ready
brown9804 Apr 15, 2025
4280955
Merge fdaa5510130a72c48887f86029c10c6202fa3ba1 into 2a85c3c9abb758a29…
brown9804 Apr 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Costa Rica
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
[brown9804](https://github.com/brown9804)

Last updated: 2025-02-21
Last updated: 2025-04-15

------------------------------------------

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

</details>

## Prerequisites

- An `Azure subscription is required`. All other resources, including instructions for creating a Resource Group, are provided in this workshop.
- `Contributor role assigned or any custom role that allows`: access to manage all resources, and the ability to deploy resources within subscription.
- If you choose to use a Terraform approach, please ensure that:
- [Terraform is installed on your local machine](https://developer.hashicorp.com/terraform/tutorials/azure-get-started/install-cli#install-terraform).
- [Install the Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) to work with both Terraform and Azure commands.

## Infrastructure as Code (IaC)

> Is crucial for modern cloud-based solutions and applications. Here is why:

<details>
<summary>1. Consistency and Reproducibility</summary>

- **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.
- **Reproducibility**: With IaC, you can `recreate your infrastructure from scratch in a consistent manner.` This is particularly useful for `disaster recovery and scaling`.

</details>

<details>
<summary>2. Version Control</summary>

- **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.`
- **Change Management**: Version control `provides a history of changes, making it easier to understand what changes were made, who made them, and why.`

</details>

<details>
<summary>3. Flexibility and Options</summary>


> 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.

- **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.`
- **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.`
- **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.

</details>

<details>
<summary>4. Enhanced Security</summary>

- **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.`
- **Compliance**: IaC helps maintain compliance with `regulatory requirements by providing a clear and auditable trail of infrastructure changes.`

</details>

<details>
<summary>5. Scalability</summary>

- **Dynamic Scaling**: IaC enables `dynamic scaling of resources based on demand.` This ensures that your infrastructure can handle varying workloads efficiently.
- **Resource Optimization**: By automating the `provisioning and de-provisioning of resources,` IaC helps optimize resource usage and reduce costs.

</details>

<details>
<summary>6. Automation</summary>

- **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.`
- **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.`

</details>


> [!TIP]
> 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).

> E.g [Demonstration: Deploying Azure Resources for a Data Platform](./Terraform)

<div align="center">
<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;"/>
</div>


<div align="center">
<h3 style="color: #4CAF50;">Total Visitors</h3>
Expand Down
13 changes: 12 additions & 1 deletion Terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Costa Rica
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
[brown9804](https://github.com/brown9804)

Last updated: 2025-03-13
Last updated: 2025-04-15

------------------------------------------

Expand Down Expand Up @@ -34,6 +34,7 @@ Last updated: 2025-03-13

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

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

## Configure Remote Storage for a Terraform deployment

> 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.

> 1. Create an Azure Storage Account: <br/>
> - Go to the Azure portal and create a new storage account (if you don't have one already). <br/>
> - Note down the storage account name and the access key. <br/>
> 2. Create a Storage Container: Within the storage account, create a new container to store the Terraform state file.
> 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.

## How to execute it

```mermaid
Expand Down
104 changes: 104 additions & 0 deletions Terraform/src/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Retrieve the client configuration of the AzureRM provider
data "azurerm_client_config" "example" {}

# Check the directory object type
data "azuread_directory_object" "example" {
object_id = data.azurerm_client_config.example.object_id
}

# Get information about the Entra user
data "azuread_user" "example" {
object_id = data.azurerm_client_config.example.object_id
}

# Local value to determine if the client is a user or not
locals {
fabric_admin = can(data.azuread_directory_object.example.type == "User") ? data.azuread_user.example.user_principal_name : data.azurerm_client_config.example.object_id
}

# Create a resource group
resource "azurerm_resource_group" "example" {
name = var.resource_group_name # Name of the resource group
location = var.location # Location of the resource group
}

# Create a storage account for remote state
resource "azurerm_storage_account" "example" {
name = var.storage_account_name
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
}

# Create a storage container for remote state
resource "azurerm_storage_container" "example" {
name = var.container_name
storage_account_name = azurerm_storage_account.example.name
container_access_type = "private"
depends_on = [azurerm_storage_account.example] # Ensure storage account is created first
}

# Create an MSSQL Server
resource "azurerm_mssql_server" "example" {
name = var.sql_server_name # Name of the SQL Server
resource_group_name = azurerm_resource_group.example.name # Resource group name
location = azurerm_resource_group.example.location # Location of the SQL Server
version = "12.0" # SQL Server version
administrator_login = var.admin_username # Administrator username
administrator_login_password = var.admin_password # Administrator password
depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
}

# Add a null resource to introduce a delay
resource "null_resource" "wait_for_sql_server" {
depends_on = [azurerm_mssql_server.example]

provisioner "local-exec" {
command = "Start-Sleep -Seconds 60"
interpreter = ["PowerShell", "-Command"]
}
}

# Create an MSSQL Database
resource "azurerm_mssql_database" "example" {
name = var.sql_database_name # Name of the SQL Database
server_id = azurerm_mssql_server.example.id # ID of the SQL Server
sku_name = "Basic" # SKU name for the SQL Database
depends_on = [null_resource.wait_for_sql_server] # Ensure SQL Server is fully provisioned first
}

# Create Microsoft Fabric Capacity
resource "azurerm_fabric_capacity" "example" {
name = "fc${var.solution_name}"
resource_group_name = azurerm_resource_group.example.name
location = var.location

administration_members = setunion([local.fabric_admin], var.fabric_capacity_admin_upns)

sku {
name = var.fabric_capacity_sku
tier = "Fabric"
}
depends_on = [azurerm_resource_group.example] # Ensure resource group is created first
}

# Get the Fabric Capacity details
data "fabric_capacity" "example" {
display_name = azurerm_fabric_capacity.example.name

lifecycle {
postcondition {
condition = self.state == "Active"
error_message = "Fabric Capacity is not in Active state. Please check the Fabric Capacity status."
}
}
}

# Create a Fabric Workspace
resource "fabric_workspace" "example" {
capacity_id = data.fabric_capacity.example.id
display_name = "ws-${var.solution_name}"
depends_on = [data.fabric_capacity.example] # Ensure Fabric Capacity data source is available first
}
33 changes: 33 additions & 0 deletions Terraform/src/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Output the name of the resource group
output "resource_group_name" {
value = azurerm_resource_group.example.name # The name of the resource group
}

# Output the name of the storage account
output "storage_account_name" {
value = azurerm_storage_account.example.name # The name of the storage account
}

# Output the name of the storage container
output "storage_container_name" {
value = azurerm_storage_container.example.name # The name of the storage container
}

# Output the name of the MSSQL Server
output "sql_server_name" {
value = azurerm_mssql_server.example.name # The name of the SQL Server
}

# Output the name of the MSSQL Database
output "sql_database_name" {
value = azurerm_mssql_database.example.name # The name of the SQL Database
}

# Output the name of the Microsoft Fabric Capacity
output "fabric_capacity_name" {
value = azurerm_fabric_capacity.example.name
}

output "fabric_workspace_name" {
value = fabric_workspace.example.display_name
}
21 changes: 21 additions & 0 deletions Terraform/src/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
terraform {
required_version = ">= 1.8, < 2.0"
# Specify the required providers and their versions
required_providers {
azurerm = {
source = "hashicorp/azurerm" # Source of the AzureRM provider
version = "~> 4.16.0" # Version of the AzureRM provider
}
fabric = {
source = "microsoft/fabric"
version = "0.1.0-beta.7"
}
}
}

provider "azurerm" {
features {} # Enable all features for the AzureRM provider
subscription_id = var.subscription_id # Add your subscription ID here
}

provider "fabric" {}
8 changes: 8 additions & 0 deletions Terraform/src/remote-storage.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
backend "azurerm" {
resource_group_name = "RGWorkshopUserName" # The name of the resource group for remote state storage
storage_account_name = "examplestorageacctworkshop" # The name of the storage account for remote state storage
container_name = "tfstate" # The name of the container for remote state storage
key = "terraform.tfstate" # The key for the remote state file
}
}
32 changes: 32 additions & 0 deletions Terraform/src/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ----------------------------------
### Here is some sample data. Please make any necessary modifications. 
# ----------------------------------

# Variable for subscription ID
subscription_id = "" # Add your subscription id number

# Resource group name
resource_group_name = "" # Add your desired RG name

# Location of the resources
location = "Central US"

# SQL Server configuration
sql_server_name = "usernamesqlserver" # replace username with your name
admin_username = "adminuser" # replace with your desired user name
admin_password = "P@ssw0rd1234" # Make sure to use a strong password

# SQL Database name
sql_database_name = "workshopdbusername" # replace username with your name

# Variables for remote state storage
storage_account_name = "storageacctworkshop01"
container_name = "tfstate"

# Variable for administrator principal ID
admin_principal_id = ""

# Microsoft Fabric Capacity configuration
solution_name = "capacitynamews" # choose your capacity name
fabric_capacity_admin_upns = ["user-email-here", "another-user-email-here"]
fabric_capacity_sku = "F64" # Choose your SKU like F64
Loading