Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add role assignments for ingress application gateway and corresponding example #426

Merged
merged 8 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 12 additions & 6 deletions README.md

Large diffs are not rendered by default.

111 changes: 111 additions & 0 deletions examples/application_gateway_ingress/k8s_workload.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
resource "kubernetes_namespace_v1" "example" {
metadata {
name = "example"
}

depends_on = [module.aks]
}

resource "kubernetes_pod" "aspnet_app" {
#checkov:skip=CKV_K8S_8:We don't need readiness probe for this simple example.
#checkov:skip=CKV_K8S_9:We don't need readiness probe for this simple example.
#checkov:skip=CKV_K8S_22:readOnlyRootFilesystem would block our pod from working
#checkov:skip=CKV_K8S_28:capabilities would block our pod from working
metadata {
labels = {
app = "aspnetapp"
}
name = "aspnetapp"
namespace = kubernetes_namespace_v1.example.metadata[0].name
}
spec {
container {
name = "aspnetapp-image"
image = "mcr.microsoft.com/dotnet/samples@sha256:7070894cc10d2b1e68e72057cca22040c5984cfae2ec3e079e34cf0a4da7fcea"
image_pull_policy = "Always"

port {
container_port = 80
protocol = "TCP"
}
resources {
limits = {
cpu = "250m"
memory = "256Mi"
}
requests = {
cpu = "250m"
memory = "256Mi"
}
}
security_context {}
}
}
}

resource "kubernetes_service" "svc" {
metadata {
name = "aspnetapp"
namespace = kubernetes_namespace_v1.example.metadata[0].name
}
spec {
selector = {
app = "aspnetapp"
}

port {
port = 80
protocol = "TCP"
target_port = 80
}
}
}

resource "kubernetes_ingress_v1" "ing" {
metadata {
annotations = {
"kubernetes.io/ingress.class" : "azure/application-gateway"
}
name = "aspnetapp"
namespace = kubernetes_namespace_v1.example.metadata[0].name
}
spec {
rule {
http {
path {
path = "/"
path_type = "Exact"

backend {
service {
name = "aspnetapp"

port {
number = 80
}
}
}
}
}
}
}

depends_on = [
module.aks,
]
}

resource "time_sleep" "wait_for_ingress" {
create_duration = "15m"

depends_on = [kubernetes_ingress_v1.ing]
}

data "kubernetes_ingress_v1" "ing" {
metadata {
name = "aspnetapp"
namespace = kubernetes_namespace_v1.example.metadata[0].name
}

depends_on = [time_sleep.wait_for_ingress]
}
194 changes: 194 additions & 0 deletions examples/application_gateway_ingress/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
resource "random_id" "prefix" {
byte_length = 8
}

resource "random_id" "name" {
byte_length = 8
}

resource "azurerm_resource_group" "main" {
count = var.create_resource_group ? 1 : 0

location = var.location
name = coalesce(var.resource_group_name, "${random_id.prefix.hex}-rg")
}

locals {
resource_group = {
name = var.create_resource_group ? azurerm_resource_group.main[0].name : var.resource_group_name
location = var.location
}
}

resource "azurerm_virtual_network" "test" {
count = var.bring_your_own_vnet ? 1 : 0

address_space = ["10.52.0.0/16"]
location = local.resource_group.location
name = "${random_id.prefix.hex}-vn"
resource_group_name = local.resource_group.name
}

resource "azurerm_subnet" "test" {
count = var.bring_your_own_vnet ? 1 : 0

address_prefixes = ["10.52.0.0/24"]
name = "${random_id.prefix.hex}-sn"
resource_group_name = local.resource_group.name
virtual_network_name = azurerm_virtual_network.test[0].name
}

locals {
appgw_cidr = !var.use_brown_field_application_gateway && !var.bring_your_own_vnet ? "10.225.0.0/16" : "10.52.1.0/24"
}

resource "azurerm_subnet" "appgw" {
count = var.use_brown_field_application_gateway && var.bring_your_own_vnet ? 1 : 0

address_prefixes = [local.appgw_cidr]
name = "${random_id.prefix.hex}-gw"
resource_group_name = local.resource_group.name
virtual_network_name = azurerm_virtual_network.test[0].name
}

# Locals block for hardcoded names
locals {
backend_address_pool_name = try("${azurerm_virtual_network.test[0].name}-beap", "")
frontend_ip_configuration_name = try("${azurerm_virtual_network.test[0].name}-feip", "")
frontend_port_name = try("${azurerm_virtual_network.test[0].name}-feport", "")
http_setting_name = try("${azurerm_virtual_network.test[0].name}-be-htst", "")
listener_name = try("${azurerm_virtual_network.test[0].name}-httplstn", "")
request_routing_rule_name = try("${azurerm_virtual_network.test[0].name}-rqrt", "")
}

resource "azurerm_public_ip" "pip" {
count = var.use_brown_field_application_gateway && var.bring_your_own_vnet ? 1 : 0

allocation_method = "Static"
location = local.resource_group.location
name = "appgw-pip"
resource_group_name = local.resource_group.name
sku = "Standard"
}

resource "azurerm_application_gateway" "appgw" {
count = var.use_brown_field_application_gateway && var.bring_your_own_vnet ? 1 : 0

location = local.resource_group.location
#checkov:skip=CKV_AZURE_120:We don't need the WAF for this simple example
name = "ingress"
resource_group_name = local.resource_group.name

backend_address_pool {
name = local.backend_address_pool_name
}
backend_http_settings {
cookie_based_affinity = "Disabled"
name = local.http_setting_name
port = 80
protocol = "Http"
request_timeout = 1
}
frontend_ip_configuration {
name = local.frontend_ip_configuration_name
public_ip_address_id = azurerm_public_ip.pip[0].id
}
frontend_port {
name = local.frontend_port_name
port = 80
}
gateway_ip_configuration {
name = "appGatewayIpConfig"
subnet_id = azurerm_subnet.appgw[0].id
}
http_listener {
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = local.frontend_port_name
name = local.listener_name
protocol = "Http"
}
request_routing_rule {
http_listener_name = local.listener_name
name = local.request_routing_rule_name
rule_type = "Basic"
backend_address_pool_name = local.backend_address_pool_name
backend_http_settings_name = local.http_setting_name
priority = 1
}
sku {
name = "Standard_v2"
tier = "Standard_v2"
capacity = 1
}

lifecycle {
ignore_changes = [
tags,
backend_address_pool,
backend_http_settings,
http_listener,
probe,
request_routing_rule,
url_path_map,
]
}
}

module "aks" {
#checkov:skip=CKV_AZURE_141:We enable admin account here so we can provision K8s resources directly in this simple example
source = "../.."

prefix = random_id.name.hex
resource_group_name = local.resource_group.name
kubernetes_version = "1.26" # don't specify the patch version!
automatic_channel_upgrade = "patch"
agents_availability_zones = ["1", "2"]
agents_count = null
agents_max_count = 2
agents_max_pods = 100
agents_min_count = 1
agents_pool_name = "testnodepool"
agents_pool_linux_os_configs = [
{
transparent_huge_page_enabled = "always"
sysctl_configs = [
{
fs_aio_max_nr = 65536
fs_file_max = 100000
fs_inotify_max_user_watches = 1000000
}
]
}
]
agents_type = "VirtualMachineScaleSets"
azure_policy_enabled = true
enable_auto_scaling = true
enable_host_encryption = true
http_application_routing_enabled = true
green_field_application_gateway_for_ingress = var.use_brown_field_application_gateway ? null : {
name = "ingress"
subnet_cidr = local.appgw_cidr
}
brown_field_application_gateway_for_ingress = var.use_brown_field_application_gateway ? {
id = azurerm_application_gateway.appgw[0].id
subnet_id = azurerm_subnet.appgw[0].id
} : null
create_role_assignments_for_application_gateway = var.create_role_assignments_for_application_gateway
local_account_disabled = false
log_analytics_workspace_enabled = false
net_profile_dns_service_ip = "10.0.0.10"
net_profile_service_cidr = "10.0.0.0/16"
network_plugin = "azure"
network_policy = "azure"
os_disk_size_gb = 60
private_cluster_enabled = false
public_network_access_enabled = true
rbac_aad = true
rbac_aad_managed = true
role_based_access_control_enabled = true
sku_tier = "Standard"
vnet_subnet_id = var.bring_your_own_vnet ? azurerm_subnet.test[0].id : null
depends_on = [
azurerm_subnet.test,
]
}
4 changes: 4 additions & 0 deletions examples/application_gateway_ingress/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "ingress_endpoint" {
depends_on = [time_sleep.wait_for_ingress]
value = "http://${data.kubernetes_ingress_v1.ing.status[0].load_balancer[0].ingress[0].ip}"
}
39 changes: 39 additions & 0 deletions examples/application_gateway_ingress/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
terraform {
required_version = ">=1.3"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.51, < 4.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "2.22.0"
}
random = {
source = "hashicorp/random"
version = "3.3.2"
}
time = {
source = "hashicorp/time"
version = "0.9.1"
}
}
}

provider "azurerm" {
features {
resource_group {
prevent_deletion_if_contains_resources = false
}
}
}

# DO NOT DO THIS IN PRODUCTION ENVIRONMENT
provider "kubernetes" {
host = module.aks.admin_host
client_certificate = base64decode(module.aks.admin_client_certificate)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is using this output from the AKS module safe ?

The most reliable way to configure the Kubernetes provider is to ensure that the cluster itself and the Kubernetes provider resources can be managed with separate apply operations. Data-sources can be used to convey values between the two stages as needed.

https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs#stacking-with-managed-kubernetes-cluster-resources

Just double checking because we don't want to introduce random CI failures

client_key = base64decode(module.aks.admin_client_key)
cluster_ca_certificate = base64decode(module.aks.admin_cluster_ca_certificate)
}

provider "random" {}
29 changes: 29 additions & 0 deletions examples/application_gateway_ingress/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
variable "create_resource_group" {
type = bool
default = true
nullable = false
}

variable "create_role_assignments_for_application_gateway" {
type = bool
default = true
}

variable "location" {
default = "eastus"
}

variable "resource_group_name" {
type = string
default = null
}

variable "use_brown_field_application_gateway" {
type = bool
default = false
}

variable "bring_your_own_vnet" {
type = bool
default = true
}
Loading
Loading