I need some help
I have one resource called Service Bus which i am creating in a resource group called Servicebus-rg . In this resourcegroup. I have one serviceBus resource only. Nothing else.
I have another Resource Group called Eventgrid-rg. This Resource has a EventGrid and Key Vault Created.
Now I want to reference the Shared Access Policies Keys of Service Bus which is in Servicebus-rg Resource Group to the Key Vault which is in EventGrid-rg. May i please know . How can i get this done via BICEP.
Below are the sample codes which i built for the understanding.
ServiceBus-Rg
param sbusname string
param sbustopicname string
param stopicsubscriptionname string
param stopicauthrulename string
param stopicsize int
param location string
var serviceBussastoken = listKeys(servicebustopic.id,servicebustopic.apiVersion).primaryKey
resource sbus 'Microsoft.ServiceBus/namespaces#2021-11-01' = {
name: sbusname
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
zoneRedundant: true
}
sku: {
name: 'Premium'
capacity: 2
tier: 'Premium'
}
tags: {
servicebus : 'test-dev'
}
}
resource servicebustopic 'Microsoft.ServiceBus/namespaces/topics#2021-11-01' = {
name: sbustopicname
parent: sbus
properties: {
status: 'Active' //can give multiple values in an array if required
supportOrdering: true //value for ordering in topic
defaultMessageTimeToLive: '14.00:00:00'
enableExpress:false
enableBatchedOperations:false
}
}
resource stopicauthrule 'Microsoft.ServiceBus/namespaces/topics/authorizationRules#2021-11-01' = {
name: stopicauthrulename
parent: servicebustopic
properties: {
rights: [
'Listen'
'Manage'
'Send'
]
}
}
resource stopicsub 'Microsoft.ServiceBus/namespaces/topics/subscriptions#2021-11-01' = {
name: stopicsubscriptionname
parent: servicebustopic
properties: {
maxDeliveryCount: 3
defaultMessageTimeToLive: '14.00:00:00'
autoDeleteOnIdle: '7.00:00:00'
lockDuration: '00:00:30'
}
}
output sbusid string = sbus.id
output sbname string = sbus.name
output sbusapi string = sbus.apiVersion
output stopicname string = servicebustopic.name
output sbustopicid string = servicebustopic.id
output servicebustopicsubscriptionname string = stopicsub.name
output servicebustopicsubsctiptionid string = stopicsub.id
output sbussastoken string = serviceBussastoken
Eventgrid-Rg
param evtgriddomainname string
param eventgriddomaintopicname string
param eventsubname string
param location string
param servicebustopicid string
param deliveryattrname string
var evtgridtoken1 = '${listKeys(eventgrid_domain.id, eventgrid_domain.apiVersion).key1}'
resource eventgrid_domain 'Microsoft.EventGrid/domains#2022-06-15' = {
name: evtgriddomainname
location: location
properties: {
autoCreateTopicWithFirstSubscription: true //to create eventtopic when eventsub is getting created
autoDeleteTopicWithLastSubscription: false
dataResidencyBoundary: 'WithinGeopair' //to enable geo replication of data
disableLocalAuth: false //TO enable this we need Azure AD
inboundIpRules: [] // to specify if we want to restrict any IP
inputSchema: 'EventGridSchema' // TO give schema like cloud, eventgrid etc
publicNetworkAccess: 'Enabled' //enabling public access by default
}
tags: {
servicename : 'eventgrid-poc'
env : 'dev'
}
}
resource eventgrid_domain_topic 'Microsoft.EventGrid/domains/topics#2022-06-15' = {
name: eventgriddomaintopicname
parent: eventgrid_domain
}
resource eventgrid_subscription 'Microsoft.EventGrid/domains/topics/eventSubscriptions#2022-06-15' = {
name: eventsubname
parent: eventgrid_domain_topic
properties: {
destination: {
endpointType: 'ServiceBusTopic'
properties: {
deliveryAttributeMappings: [
{
type: 'Static'
name: deliveryattrname
properties: {
isSecret: false
value: 'not-a-secreat-1234'
}
}
]
resourceId: servicebustopicid
}
}
}
}
output eventgriddomainname string = eventgrid_domain.name
output eventgriddomainid string = eventgrid_domain.id
output eventdomaintopicname string = eventgrid_domain_topic.name
output eventdomaintopicid string = eventgrid_domain_topic.id
output eventgridtoken string = evtgridtoken1
Now my Keyvault.Bicep is like this.
resource keyvault 'Microsoft.KeyVault/vaults#2022-07-01' = {
name: keyvaultname
location: location
properties: {
sku: {
family: 'A'
name: 'premium'
}
tenantId: tenantid
accessPolicies: [
resource keyvault 'Microsoft.KeyVault/vaults#2022-07-01' = {
name: keyvaultname
location: location
properties: {
sku: {
family: 'A'
name: 'premium'
}
tenantId: tenantid
accessPolicies: [
{
permissions: {
keys: [
'all'
]
secrets: [
'all'
]
}
tenantId: tenantid
objectId: Eventgridtokenid
{
permissions: {
keys: [
'all'
]
secrets: [
'all'
]
}
tenantId:tenantid
objectId: servicebustopicid
}
]
}
resource EventgridSecret 'Microsoft.KeyVault/vaults/secrets#2022-07-01' = {
parent: keyvault
name: eventgridtokenname
properties: {
value: eventgridtoken
attributes: {
enabled: true
}
}
}
//create keyvaukt secret for service bus topic token
resource servicebustopicsecret 'Microsoft.KeyVault/vaults/secrets#2022-07-01' = {
name:servicebustopic
parent: keyvault
properties: {
value: servicebustopictoken
attributes: {
enabled: true
}
}
}
Now the issue i am facing is. How do i reference the ServiceBus Topic Token in Main.bicep file as it is in different ResourceGroup than the EventGrid Resource Group where the Keyvault resides.
Can someone please help me on this.
Related
I need to create an eventarc trigger on a Pub/Sub message published. I do not know where to put the Pub/Sub topic ID.
resource "google_eventarc_trigger" "eventarc_trigger" {
name = "test-trigger"
service_account = var.service_account
project = local.project
location = local.region
destination {
workflow = google_workflows_workflow.example.id
}
matching_criteria {
attribute = "type"
value = "google.cloud.pubsub.topic.v1.messagePublished"
}
}
You can define the target transport like that
resource "google_eventarc_trigger" "eventarc_trigger" {
name = "test-trigger"
service_account = var.service_account
project = local.project
location = local.region
destination {
workflow = google_workflows_workflow.example.id
}
matching_criteria {
attribute = "type"
value = "google.cloud.pubsub.topic.v1.messagePublished"
}
transport {
pubsub {
topic = "projects/{PROJECT_ID}/topics/{TOPIC_NAME}"
}
}
}
I have defined variable users:
users = [
{
userName = "john.doe"
roles = ["ORG_ADMIN"]
profile_attributes = null
appId = null
},
{
userName = "doe.john"
roles = ["ORG_ADMIN"]
profile_attributes = <<EOT
{
"testParameter":"value"
}
EOT
appId = "test123"
}
]
and now I want to create okta_app_user resource:
resource "okta_app_user" "app_users" {
count = length(var.users)
app_id = var.users[count.index].appId
user_id = okta_user.users[count.index].id
username = "${var.users[count.index].userName}#example.com"
profile = var.users[count.index].profile_attributes
}
but app_id can't be empty in this resource but may be empty in my configuration. Is it possible to skip that user in okta_app_user when var.users[count.index].appId is empty ?
so something similar to what can be achieved:
foreach($users in $user) {
if (!$user.app_id) {
continue;
}
}
Yes, you can filter out users without the appId. For example, by creating helper local variable users_with_appId:
locals {
users_with_appId = [
for user in var.users: user if user.appId != null
]
}
And then:
resource "okta_app_user" "app_users" {
count = length(local.users_with_appId)
app_id = local.users_with_appId[count.index].appId
user_id = okta_user.users[count.index].id
username = "${local.users_with_appId[count.index].userName}#example.com"
profile = local.users_with_appId[count.index].profile_attributes
}
In the above its not clear what okta_user.users[count.index].id is? Thus further adjustments may be needed.
Looking for a cleaner/more-readable way to achieve a nested loop in Terraform. I will illustrate with an example.
Let's say we have variable for roles that looks like this:
variable "roles" {
type = "list"
default = [
{
name = "LOADER"
schemas = {
RAW = ["USAGE", "ALL"]
SRC = ["ALL"]
}
},
{
name = "USER"
schemas = {
RAW = ["DELETE", "OBJECT"]
SRC = ["USE"]
}
}
]
}
From this, I want to end up with a List of dictionaries that looks something like:
output = [
{
"privilege" = "USAGE"
"role" = "LOADER"
"schema" = "RAW"
},
{
"privilege" = "ALL"
"role" = "LOADER"
"schema" = "RAW"
},
{
"privilege" = "ALL"
"role" = "LOADER"
"schema" = "SRC"
},
{
"privilege" = "DELETE"
"role" = "USER"
"schema" = "RAW"
},
{
"privilege" = "OBJECT"
"role" = "USER"
"schema" = "RAW"
},
{
"privilege" = "USE"
"role" = "USER"
"schema" = "SRC"
},
]
What I have tried so far (seems to work but I am looking for a more concise/readable way to do it):
locals {
# FlatMapping to a list of dictionaries. Each dict in the form of {schema=<schema>, role=<role>, privilege=<privilege>}
key_val = [for role in var.roles : [for schema, privilege in role["schemas"]: {
role = role["name"]
schema = schema
privilege = privilege
}]]
other_key_val = [for dict in flatten(local.key_val): [for priv in dict["privilege"]: {
role = dict["role"]
schema = dict["schema"]
privilege = priv
}]]
}
output "output" {
value = flatten(local.other_key_val)
}
My main objective is to have readable code that can be understood better by others. Given that I am using loops in Terraform for the first time, I can't judge if my implementation is considered readable.
Maybe this would be a little bit simpler way to achieve the same result:
locals {
roles = [
{
name = "LOADER"
schemas = {
RAW = ["USAGE", "ALL"]
SRC = ["ALL"]
}
},
{
name = "USER"
schemas = {
RAW = ["DELETE", "OBJECT"]
SRC = ["USE"]
}
}
]
out = flatten([
for item in local.roles: [
for schema, privileges in item.schemas: [
for privilege in privileges: {
role = item.name
privilege = privilege
schema = schema
}
]
]
])
}
I want to create a dynamic block that will able to dynamically create envs for docker container inside kubernetes using terraform.
I already tried creating a var of list and iterate over the envs but I am getting syntax error
Error: Reference to "count" in non-counted context
on kubernetes/kubernetes.main.tf line 68, in resource "kubernetes_deployment" "kube_deployment":
This is due to usage of count out of resource block.
I am looking now to create multiple envs like this
...
env {
name = "NAME"
value = "VALUE"
}
env {
name = "NAME"
value = "VALUE"
}
.
.
.
is there anyway to create this iteration or any hacks to create dynamic envs in container block. I understand that dynamic blocks are only inside resource, data, provider, and provisioner.
I was previously using helm to do this kind of templating but now I want to fully move to terraform.
I would love any directions to solve such issue.
Thanks
resource "kubernetes_deployment" "kube_deployment" {
metadata {
name = var.deployment_name
labels = {
App = var.deployment_name
}
}
spec {
replicas = 1
selector {
match_labels = {
App = var.deployment_name
}
}
template {
metadata {
labels = {
App = var.deployment_name
}
}
spec {
container {
image = var.container_image
name = var.container_name
env {
name = "NAME"
value = "VALUE"
}
port {
container_port = var.container_port
}
}
}
}
}
}
It was actually possible even if inside nested block of type resource, data, provider, and provisione..
here is a working code
resource "kubernetes_deployment" "kube_deployment" {
metadata {
name = var.deployment_name
labels = {
App = var.deployment_name
}
}
spec {
replicas = 1
selector {
match_labels = {
App = var.deployment_name
}
}
template {
metadata {
labels = {
App = var.deployment_name
}
}
spec {
container {
image = var.container_image
name = var.container_name
dynamic "env" {
for_each = var.envs
content {
name = env.value.name
value = env.value.value
}
}
port {
container_port = var.container_port
}
}
}
}
}
}
def builder = new groovy.json.JsonBuilder()
def root = builder.auth {
identity {
methods (['password'])
password {
user {
name {
usrName
domain {
id usrDomain
}
password "openstack"
}
}
}
scope {
project {
name prjName
domain {
id 'default'
}
}
}
}
}
assert builder.toString() == '{"auth":{"identity":{"methods":["password"],"password": {"user":{"name":"admin","domain":{"id":"default"},"password":"openstack"}}},"scope":{"project":{"name":"admin","domain":{"id":"default"}}}}}'
assert output:
Assertion failed:
assert builder.toString() == '{"auth":{"identity":{"methods":["password"],"password": {"user":{"name":"admin","domain":{"id":"default"},"password":"openstack"}}},"scope":{"project":{"name":"admin","domain":{"id":"default"}}}}}'
| | |
| | false
| '{"auth":{"methods":["password"],"password":{"user":{"name":{"domain":{"id":"Default"},"password":"openstack"}}},"scope":{"project":{"name":"admin","domain":{"id":"default"}}}}}'
{"auth":{"methods":["password"],"password":{"user":{"name":{"domain":{"id":"Default"},"password":"openstack"}}},"scope":{"project":{"name":"admin","domain":{"id":"default"}}}}}
Basically the "identity" key is ignored.
I have seen that there is a method called "identity" belonging to DefaultGroovyMethods, but I have no ideea how to overcome this.
First time writing Groovy, have a little background in Python. Any help is apreciated!
Complete solution done with Szymon Stepniak's answer (and other corrections to json declaration):
def builder = new groovy.json.JsonBuilder()
builder auth: [
identity: {
methods(['password'])
password {
user {
name "$usrName"
domain {
id usrDomain
}
password "openstack"
}
}
},
scope: {
project {
name prjName
domain {
id 'default'
}
}
}
]
assert builder.toString() == '{"auth":{"identity":{"methods":["password"],"password":{"user":{"name":"admin","domain":{"id":"default"},"password":"openstack"}}},"scope":{"project":{"name":"admin","domain":{"id":"default"}}}}}'
Just in case someone wants to follow along this example.
To overcome this limitation (closure passed to JsonBuilder.call() method resolves identity method in the delegation chain), you will need to either represent your JSON document as a map or at least use a map up to identity key and from this place you can use a closure.
def builder = new groovy.json.JsonBuilder()
builder auth: [
identity: {
methods (['password'])
password {
user {
name {
usrName
domain {
id usrDomain
}
password "openstack"
}
}
}
scope {
project {
name prjName
domain {
id 'default'
}
}
}
}
]
Also, keep in mind that the closure you defined does not produce the expected JSON string, but it will have identity key that you are missing in the closure example.