How to assign members to groups iterating a CSV file - azure-active-directory

I would like to assign members to Azure Active Directory groups after creating them using Terraform and the resources "azuread_group_member", "azuread_group" and "azuread_user".
First of all, I have a CSV file that has a relationship between users and departments:
first_name,last_name,department
UserName1,LastName1,Department1
UserName2,LastName2,Department2
And other CSV file containing the groups:
department_name
Department1
Department2
Then, I have a local variable that is reading these CSV files:
locals {
users = csvdecode(file("${path.module}/users.csv"))
groups = csvdecode(file("${path.module}/aad_groups.csv"))
}
Next, I create the users:
# Create users
resource "azuread_user" "users" {
for_each = { for user in local.users : user.first_name =\> user }
user_principal_name = format(
"%s#%s",
each.value.employee_id,
"mydomain.com"
)
}
Following, I create the groups iterating the groups.csv
# Create groups resource
"azuread_group" "groups" {
for_each = { for group in local.groups : group.deparment_name => group }
display_name = each.value.deparment_name
security_enabled = true }
But now, I would like assign members, with "azuread_group_member" to the groups using the relationship that I have in users.csv, in the column "department"
How can I do that?

I have created users and groups as below.
locals {
users = {
"john#xxumail.onmicrosoft.com" = { first_name = "John", last_name = "Doe" , password = "xxx#123",department = "Marketing Department" },
"jane#xxxxmail.onmicrosoft.com" = { first_name = "Jane", last_name = "Doe" , password = "xxx#123",department = "IT Department"}
}
}
locals {
groups = {
"Marketing Department" = { display_name = "Marketing Department" },
"Sales Department" = { display_name = "Sales Department" },
"IT Department" = { display_name = "IT Department" }
}
}
resource "azuread_user" "users" {
for_each = local.users
display_name = "${each.value.first_name} ${each.value.last_name}"
mail_nickname = each.value.first_name
user_principal_name = each.key
password = each.value.password
department = each.value.department
}
resource "azuread_group" "departments" {
for_each = local.groups
display_name = each.value.display_name
security_enabled = true
mail_enabled =false
}
Here note that group key value must match the user department value.
example : Marketing Department , which equals user department of John Doe
resource "azuread_group_member" "group_members" {
for_each = local.users
group_object_id = azuread_group.departments[each.value.department].object_id
member_object_id = azuread_user.users[each.key].object_id
}
With the above mapping i could add the users based on their department to groups .

Related

Assign random passwords while creating multiple Azure Active Directory users with Terraform reading a CSV file

I am trying to assign random passwords to multiple AAD users -in a csv file- with Terraform and resources "azuread_user"
First of all, I have this CSV file with some users:
user_name
User1
User2
User3
User4
Following, I read this CSV file using:
locals {
users = csvdecode(file("${path.module}/users.csv"))
}
Then, using "random_password" resource, I am generating a new password:
resource "random_password" "password" {
length = 16
special = true
override_special = "!#$%&*()-_=+[]{}<>:?"
}
Next, with "azuread_user" I am trying to create the user with the password generated:
resource "azuread_user" "users" {
for_each = { for user in local.users : user.first_name => user }
user_principal_name = format(
"%s#%s",
each.value.user_name,
"mydomain.com"
)
password = each.value.password
display_name = "${each.value.first_name} ${each.value.last_name}"
}
but the problem is that every user has the same password from resource "random_password" "password".
How can I assign a randomly password for each user?
I tried to create users with random passwords as below:
locals {
users = {
"divv#xxxxxxx.onmicrosoft.com" = { first_name = "John", last_name = "Doe" , department = "Marketing Department" },
"shrav#xxxxxxxxxx.onmicrosoft.com" = { first_name = "Jane", last_name = "Doe" , department = "IT Department"}
}
}
resource "random_password" "passwords" {
for_each = local.users
length = 16
special = true
}
resource "azuread_user" "users" {
for_each = local.users
display_name = "${each.value.first_name} ${each.value.last_name}"
mail_nickname = each.value.first_name
user_principal_name = each.key
password = random_password.passwords[each.key].result
department = each.value.department
}
In order to check if random passwords are generated I stored them in keyvault and checked .
They seem to be different for different user.
resource "azurerm_key_vault" "example" {
name = "kavyaexmplekeyvault"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
enabled_for_disk_encryption = true
tenant_id = data.azurerm_client_config.current.tenant_id
soft_delete_retention_days = 7
purge_protection_enabled = false
sku_name = "standard"
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
key_permissions = [
"Create",
"Get",
]
secret_permissions = [
"Set",
"Get",
"Delete",
"Purge",
"Recover",
"List"
]
storage_permissions = [
"Get","Set"
]
}
}
resource "azurerm_key_vault_secret" "password_one" {
for_each = local.users
name = "passwrdone${each.value.first_name}"
value = random_password.passwords[each.key].result
key_vault_id = azurerm_key_vault.example.id
}
Password for jane:
Password for john:

Restrict more then 2 contacts that saved on Account object

I want to build a trigger on contact, that accept check box. And In Account object it take 2 contacts that are active. when user assign 3rd active contact to the same account he/she will get error messege. how can it possible? i completed all codes but these limit of 2 contacts are pending. can anyone try to guide me how to do this?
trigger ContactTrigger on Contact(after insert, after update, after delete, after undelete) {
switch on Trigger.operationType {
when AFTER_INSERT {
Set<Id> accountIds = new Set<Id>();
for (Contact con : Trigger.new) {
if (String.isNotBlank(con.AccountId)) {
//write automation logic here
accountIds.add(con.AccountId);
}
}
// get aggregate result for all accounts
List<AggregateResult> results = [
SELECT AccountId, COUNT(Id) totalContacts
FROM Contact
WHERE Active__c = TRUE AND AccountId IN :accountIds
GROUP BY AccountId
];
integer var = results.size();
// build final list of accounts to update
List<Account> accountsToUpdate = new List<Account>();
for (AggregateResult result : results) {
// get account id and number of active contacts
String accId = String.valueOf(result.get('AccountId'));
Integer totalContacts = Integer.valueOf(result.get('totalContacts'));
// make sure you use Id feild in your account to update it
Account acc = new Account(Id = accId, Active_Contacts__c = totalContacts);
accountsToUpdate.add(acc);
}
// update the final list of account
update accountsToUpdate;
}
when AFTER_UPDATE {
Set<Id> accountIds = new Set<Id>();
for (Contact con : Trigger.new) {
// capture the account id only if active checkbox value is flipped
if (String.isNotBlank(con.AccountId) && Trigger.oldMap.get(con.Id).Active__c != con.Active__c) {
// write automation logic here
accountIds.add(con.AccountId);
} else if (Trigger.oldMap.get(con.Id).AccountId != con.AccountId) {
accountIds.add(con.AccountId);
accountIds.add(Trigger.oldMap.get(con.Id).AccountId);
}
}
// get aggregate result for all accounts
List<AggregateResult> results = [
SELECT AccountId, COUNT(Id) totalContacts
FROM Contact
WHERE Active__c = TRUE AND AccountId IN :accountIds
GROUP BY AccountId
];
// build final list of accounts to update
List<Account> accountsToUpdate = new List<Account>();
for (AggregateResult result : results) {
// get account id and number of active contacts
String accId = String.valueOf(result.get('AccountId'));
Integer totalContacts = Integer.valueOf(result.get('totalContacts'));
// make sure you use Id feild in your account to update it
Account acc = new Account(Id = accId, Active_Contacts__c = totalContacts);
accountsToUpdate.add(acc);
}
// update the final list of account
update accountsToUpdate;
}
}
}

How to create AD nested groups using GraphServiceClient c#?

Is it possible to create nested groups in Azure AD using Graph API client as:
You could use AdditionalData to add members in the step of creating groups in C#.
The example creates a Security group with an owner and members
specified. Note that a maximum of 20 relationships, such as owners and
members, can be added as part of group creation.
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantID)
.WithClientSecret(clientSecret)
.Build();
ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
// Create group B and add members(user-id1 and user-id2)
var additionalDataGroupB = new Dictionary<string, object>()
{
{"members#odata.bind", new List<string>()}
};
(additionalData["members#odata.bind"] as List<string>).Add("https://graph.microsoft.com/v1.0/users/{id1}");
(additionalData["members#odata.bind"] as List<string>).Add("https://graph.microsoft.com/v1.0/users/{id2}");
var groupB = new Group
{
Description = "Group B",
DisplayName = "PamelaGroupB",
GroupTypes = new List<String>()
{
},
MailEnabled = false,
MailNickname = "operations2019",
SecurityEnabled = true,
AdditionalData = additionalDataGroupB
};
Group groupBRequest = await graphClient.Groups.Request().AddAsync(groupB);
string groupB_id = groupBRequest.Id;
// Create group C
......
string groupC_id = groupCRequest.Id;
// Create group A and add members(groupB and groupC)
var additionalDataGroupA = new Dictionary<string, object>()
{
{"members#odata.bind", new List<string>()}
};
(additionalData["members#odata.bind"] as List<string>).Add("https://graph.microsoft.com/v1.0/groups/" + groupB_id);
(additionalData["members#odata.bind"] as List<string>).Add("https://graph.microsoft.com/v1.0/groups/" + groupC_id);
var groupA = new Group
{
Description = "Group A",
DisplayName = "PamelaGroupA",
GroupTypes = new List<String>()
{
},
MailEnabled = false,
MailNickname = "XXXXX",
SecurityEnabled = true,
AdditionalData = additionalDataGroupA
};
await graphClient.Groups.Request().AddAsync(groupA);

Update a particular field in django forms and not be able to edit the others

I am trying to create a expense claim app, i have created a form where a user can claim a expense ,when the admin Logs in the following webpage in the picture appears and the webpages iterates all the claims that have claim_status == Null, i want the admin to be able to accept or reject the claim from the dropdown and it to update the value for that object in the database and webpage to refresh and that claim showing no more
I have given a initial value of Null for the ExpenseClaim model and when user fills the expense claim form he cannot see the claim_status field
please see my models
class ExpenseClaim(models.Model):
reference_number = models.AutoField(primary_key=True)
employee_name = models.CharField(max_length=150)
employee_ID = models.CharField(max_length=150)
claim_initiating_date = models.DateTimeField(auto_now=True)
invoice_date = models.DateField()
invoice_location = models.CharField(max_length=150)
biller_name = models.CharField(max_length=150)
invoice_category = models.CharField(max_length=150)
price = models.DecimalField(decimal_places=2, max_digits=10, null=False , default=0.00)
GST = models.DecimalField(decimal_places=2 ,max_digits=10, null=False , default=0.00)
CGST = models.DecimalField(decimal_places=2 ,max_digits=10, null=False , default=0.00)
IGST = models.DecimalField(decimal_places=2, max_digits=10, null=False , default=0.00)
Total_amount = models.DecimalField(decimal_places=2 ,max_digits=10, null=False , default=0.00)
mode_of_payement = models.CharField(max_length=20)
Payment_reference = models.BooleanField()
invoice = models.FileField()
claim_status = models.CharField(default=None , max_length=10)
payment_status = models.CharField(default= None , max_length=10)
Following is my models field i tried to create a new form but that just creates a new object in the database i want to update the existing one
invoice_category_choices =[
('food',"food"),
('travel',"travel"),
('accodmodation',"accomodation"),
('fuel',"fuel"),
# ('others',"others"),
]
claim_status_choices = [
('accepted' , 'accepted'),
('rejected' , 'rejected')
]
payment_status_choices =[
('paid' , 'paid'),
('notpaid' , 'notpaid')
]
class ExpenseClaimForm(forms.ModelForm):
class Meta:
model = ExpenseClaim
exclude = [
"employee_name",
"employee_ID",
"claim_status",
"payment_status"
]
widgets = {
'invoice_date': forms.DateInput(format=('%m/%d/%Y'), attrs={'class':'form-control', 'placeholder':'Select a date', 'type':'date'}),
'invoice_category':forms.Select(choices= invoice_category_choices),
'claim_status':forms.Select(choices= claim_status_choices)
}
class ClaimStatusForm(forms.ModelForm):
class Meta:
model = ExpenseClaim
fields = [
"claim_status",
]
widgets = {
'claim_status':forms.Select(choices= claim_status_choices)
}
forms.py
class ClaimStatusForm(forms.ModelForm):
class Meta:
model = ExpenseClaim
fields = [
"claim_status",
]
widgets = {
'claim_status':forms.Select(choices= claim_status_choices)
}
views .py
def admin_update_view(request , reference_number):
post = get_object_or_404(ExpenseClaim , reference_number=reference_number)
form = ClaimStatusForm(instance=post)
if request.method == 'POST':
post = get_object_or_404(ExpenseClaim , reference_number=reference_number)
form = ClaimStatusForm(request.POST)
if form.is_valid():
claim_status = form.cleaned_data.get('claim_status')
post.claim_status = claim_status
post.save()
return redirect('/admin/')
context = { "form":form , "initialize_context" : initialize_context(request)}
return render(request , 'graphauth/adminupdate.html' , context)
urls.py
path('adminupdate/<int:reference_number>', views.admin_update_view , name='adminupdate'),
admin.html
update

terraform database creation in athena

I am trying to create a database using terraform and this seems very complicated for a poor query...
Could you help me, please?
I have tried null_resource with local-exec and data "external" Python...
I think I am looking the wrong way
ex which doesn't works in terraform 0.12
resource "null_resource" "create-endpoint" {
provisioner "local-exec" {
query = <<EOF
{
CREATE EXTERNAL TABLE `dashboard_loading_time`(
`timestamp_iso` string,
`app_identification` struct<service:string,app_name:string,app_type:string,stage:string>,
`user` struct<api_gateway_key:struct<id:string,name:string>,mashery_key:struct<id:string,name:string>,employee:struct<id:string,name:string>>,
`action` struct<action_type:string,path:string>,
`result` struct<status:string,http_status:string,response:struct<response:string>>)
PARTITIONED BY (
`year` int)
ROW FORMAT SERDE
'org.openx.data.jsonserde.JsonSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
's3://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/dev'
}
EOF
command = "aws athena start-query-execution --query-string "query""
}
}
I would like to find the simplest way to do this using terraform.
If you wanna make it for athena, need to make glue resources.
try below code with terraform.
variable "service_name" {
default = "demo-service"
}
variable "workspace" {
default = "dev"
}
variable "columns" {
default = {
id = "int"
type = "string"
status = "int"
created_at = "timestamp"
}
}
resource "aws_glue_catalog_database" "athena" {
name = "${var.service_name}_db"
}
resource "aws_glue_catalog_table" "athena" {
name = "${var.service_name}_logs"
database_name = "${aws_glue_catalog_database.athena.name}"
table_type = "EXTERNAL_TABLE"
parameters = {
EXTERNAL = "TRUE"
}
storage_descriptor {
location = "s3://${var.service_name}-${var.workspace}-data-pipeline/log/"
input_format = "org.apache.hadoop.mapred.TextInputFormat"
output_format = "org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat"
ser_de_info {
name = "jsonserde"
serialization_library = "org.openx.data.jsonserde.JsonSerDe"
parameters = {
"serialization.format" = "1"
}
}
dynamic "columns" {
for_each = "${var.columns}"
content {
name = "${columns.key}"
type = "${columns.value}"
}
}
}
partition_keys {
name = "year"
type = "string"
}
partition_keys {
name = "month"
type = "string"
}
partition_keys {
name = "day"
type = "string"
}
partition_keys {
name = "hour"
type = "string"
}
}
refer to this repository : aws-serverless-data-pipeline-by-terraform
resource "aws_glue_catalog_table" "aws_glue_catalog_table" {
name = "mytable"
database_name = aws_glue_catalog_database.aws_glue_catalog_database.name
table_type = "EXTERNAL_TABLE"
parameters = {
"classification" = "json"
}
storage_descriptor {
location = "s3://mybucket/myprefix"
input_format = "org.apache.hadoop.mapred.TextInputFormat"
output_format = "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat"
ser_de_info {
name = "myserdeinfo"
serialization_library = "org.openx.data.jsonserde.JsonSerDe"
parameters = {
"paths" = "jsonrootname"
}
}
columns {
name = "column1"
type = "array<struct<resourcearn:string,tags:array<struct<key:string,value:string>>>>"
}
}
partition_keys {
name = "part1"
type = "string"
}
partition_keys {
name = "part2"
type = "string"
}
}

Resources