CiscoISE / terraform-provider-ciscoise

Terraform Provider for Cisco ISE
https://registry.terraform.io/providers/CiscoISE/ciscoise/latest/docs
MIT License
9 stars 4 forks source link

Need a resource that relates to the '/ers/config/activedirectory/{{id}}/addGroups' PUT API call #63

Closed aussietexan closed 1 year ago

aussietexan commented 1 year ago

Is your feature request related to a problem? Please describe. There is a particular order-of-operations most often used when adding Active Directory groups in ISE.

  1. Create the AD Join Point
  2. Join the node(s) to the domain
  3. Query the domain for the required groups and add them to ISE

The domain query to find and add the necessary AD groups (name, SID, type) cannot happen until the nodes are joined to the domain.

Describe the solution you'd like We need a resource for 'ciscoise_active_directory_add_groups' that uses the 'addGroups' API as documented here: https://developer.cisco.com/docs/identity-services-engine/v1/#!activedirectory

This would allow building a terraform workflow that suits the order-of-operations required by ISE:

  1. Create the AD Joint Point using the 'ciscoise_active_directory' resource
  2. Join the node(s) to the domain using the 'ciscoise_active_directory_join_domain_with_all_nodes' resource
  3. Query the domain for the required groups using the 'ciscoise_active_directory_get_groups_by_domain_info' data source
  4. Add the required groups to ISE using the info captured from the above query

Describe alternatives you've considered The AD groups can be included at the time of the AD Join Point creation (using the 'ciscoise_active_directory' resource), but only if the SID is known beforehand. This would require either using the ISE GUI to search and find the SID, using the ISE API separately to find the SID, or getting the SID directly from AD.

fmunozmiranda commented 1 year ago

Hey @aussietexan , there's no an unique resource because it is a trigger on ciscoise_active_directory resource, if you add groups, it will call to /ers/config/activedirectory/{{id}}/addGroups API.

aussietexan commented 1 year ago

Hi @fmunozmiranda. I'm not sure I see how that would work given ISE has to be joined to the domain first before we can do a lookup to find the group name/SID/type attributes.

I tried creating a second resource block using the 'ciscoise_active_directory' resource to add the groups, but I get an error from the API stating "Failed to create Active Directory. Domain Name is not unique in the deployment"

TF code

resource "ciscoise_active_directory" "tui-ad" {
  provider = ciscoise.ise31-2
  parameters {

    ad_attributes {

      #attributes {}
    }
    ad_scopes_names = "Default_Scope"
    adgroups {

      #groups { }
    }
    description              = ""
    domain                   = var.domain_name
    name                     = var.join_point_name
  }
}

output "ciscoise_active_directory_id" {
  value = ciscoise_active_directory.tui-ad.parameters[0].id
}

resource "ciscoise_active_directory_join_domain_with_all_nodes" "tui-ad" {
  provider = ciscoise.ise31-2
  lifecycle {
    create_before_destroy = true
  }
  parameters {
    id = ciscoise_active_directory.tui-ad.parameters[0].id
    additional_data {

      name  = "username"
      value = var.ad_admin_name
    }
    additional_data {

      name  = "password"
      value = var.ise-password
    }
  }
}

resource "ciscoise_active_directory" "tui-ad-groups" {
  provider = ciscoise.ise31-2
  parameters {

    ad_attributes {

      #attributes {}
    }
    ad_scopes_names = "Default_Scope"
    adgroups {

      groups {
        name = "domain.com/Users/Domain Computers"
        sid  = "S-1-5-21-3064845550-2309088537-4239914413-515"
        type = "GLOBAL"
       }
    }
    description              = ""
    domain                   = var.domain_name
    name                     = var.join_point_name
  }
}

Without having to update the code after doing the domain join operation and getting the information from the data source, can you suggest how this workflow could be accomplished with a single 'ciscoise_active_directory' resource?

fmunozmiranda commented 1 year ago

@aussietexan , if you don´t want that error you should make a terraform import of the pre-existing resource, or you can turn true the provider variable enable_auto_import. Here´s documentation about it.https://registry.terraform.io/providers/CiscoISE/ciscoise/latest/docs#example-usage Trigger of addGroups endpoint is in Update terraform context, you may follow next steps to add a group.

  1. Create or import an ciscoise_active_directory resource.
  2. Add the adGroup struct, so terraform will detect a change, and call addGroup API.
aussietexan commented 1 year ago

Hi @fmunozmiranda. I enabled the auto import setting in the provider and added the second resource block with the same AD domain settings with the added adGroup attributes. When I run in, the AD join point is created, but I get the following error when it tries to run the second resource block to add the groups.

Error

│ Error: Failure when executing CreateActiveDirectory
│ 
│   with ciscoise_active_directory.tui-ad-groups,
│   on ad_join.tf line 62, in resource "ciscoise_active_directory" "tui-ad-groups":
│   62: resource "ciscoise_active_directory" "tui-ad-groups" {
│ 
│ error with operation CreateActiveDirectory
│ {
│   "ERSResponse" : {
│     "operation" : "POST-create-activedirectory",
│     "messages" : [ {
│       "title" : "com.cisco.epm.pap.api.exceptions.TransactionFailureException: TransactionFailureException~Failed to creation of Resource Name: NAC Group:NAC:DictionaryBucket:TUI-AD",
│       "type" : "ERROR",
│       "code" : "CRUD operation exception"
│     } ],
│     "link" : {
│       "rel" : "related",
│       "href" : "https://192.168.222.54:9060/ers/config/activedirectory",
│       "type" : "application/xml"
│     }
│   }
│ }

Code

resource "ciscoise_active_directory" "tui-ad" {
  provider = ciscoise.ise31-2
  parameters {

    ad_attributes {

      #attributes {}
    }
    ad_scopes_names = "Default_Scope"
    adgroups {

      #groups {}
    }
    description              = ""
    domain                   = var.domain_name
    name                     = var.join_point_name
  }
}

resource "ciscoise_active_directory_join_domain_with_all_nodes" "tui-ad" {
  provider = ciscoise.ise31-2
  lifecycle {
    create_before_destroy = true
  }
  parameters {
    id = ciscoise_active_directory.tui-ad.parameters[0].id
    additional_data {

      name  = "username"
      value = var.ad_admin_name
    }
    additional_data {

      name  = "password"
      value = var.ise-password
    }
  }
}

resource "ciscoise_active_directory" "tui-ad-groups" {
  provider = ciscoise.ise31-2
  parameters {

    ad_attributes {

      #attributes {}
    }
    ad_scopes_names = "Default_Scope"
    adgroups {

      groups {
        name = "domain.com/Users/Domain Computers"
        sid  = "S-1-5-21-3064845550-2309088537-4239914413-515"
        type = "GLOBAL"
       }
    }
    description              = ""
    domain                   = var.domain_name
    name                     = var.join_point_name
  }
}

If I do the run again immediately (without changes), it appears to complete but the group is not actually added in ISE.

ciscoise_active_directory.tui-ad: Refreshing state... [id=id:=252862b0-4ffc-11ed-beb0-56d4acca1b2a\name:=TUI-AD]
ciscoise_active_directory_join_domain_with_all_nodes.tui-ad: Refreshing state... [id=1666217989]

Terraform used the selected providers to generate the following execution plan. Resource actions
are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # ciscoise_active_directory.tui-ad-groups will be created
  + resource "ciscoise_active_directory" "tui-ad-groups" {
      + id           = (known after apply)
      + item         = (known after apply)
      + last_updated = (known after apply)

      + parameters {
          + ad_scopes_names            = "Default_Scope"
          + description                = ""
          + domain                     = "trappedunderise.com"
          + enable_domain_allowed_list = (known after apply)
          + enable_domain_white_list   = (known after apply)
          + id                         = (known after apply)
          + link                       = (known after apply)
          + name                       = (sensitive)

          + ad_attributes {
            }

          + adgroups {
              + groups {
                  + name = "domain.com/Users/Domain Computers"
                  + sid  = "S-1-5-21-3064845550-2309088537-4239914413-515"
                  + type = "GLOBAL"
                }
            }
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.
ciscoise_active_directory.tui-ad-groups: Creating...
ciscoise_active_directory.tui-ad-groups: Creation complete after 1s [id=id:=252862b0-4ffc-11ed-beb0-56d4acca1b2a\name:=TUI-AD]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Doing this also causes an issue when I execute a destroy...

│ Error: Failure when executing DeleteActiveDirectoryByID
│ 
│ error with operation DeleteActiveDirectoryById
│ {
│   "ERSResponse" : {
│     "operation" : "DELETE-delete-activedirectory",
│     "messages" : [ {
│       "title" : "com.cisco.cpm.nsf.api.exceptions.NSFEntityDeleteFailed: com.cisco.cpm.nsf.api.exceptions.NSFEntityDeleteFailed: java.rmi.RemoteException: Resource 'NAC Group:NAC:TUI-AD' dosen't exists.",
│       "type" : "ERROR",
│       "code" : "CRUD operation exception"
│     } ],
│     "link" : {
│       "rel" : "related",
│       "href" : "https://192.168.222.54:9060/ers/config/activedirectory/252862b0-4ffc-11ed-beb0-56d4acca1b2a",
│       "type" : "application/xml"
│     }
│   }
│ }
fmunozmiranda commented 1 year ago

Hey @aussietexan, why do you need to add the groups later? could it be added from the first active_directory resource you have?

aussietexan commented 1 year ago

Hi @fmunozmiranda. There is a particular order-of-operations most often used when adding Active Directory groups in ISE.

Create the AD Join Point
Join the node(s) to the domain
Query the domain for the required groups and add them to ISE

The domain query to find and add the necessary AD groups (name, SID, type) cannot happen until the nodes are joined to the domain.

The AD groups can be included at the time of the AD Join Point creation (using the 'ciscoise_active_directory' resource), but only if the SID is known beforehand. Without joining ISE to the domain and doing the query, the only way to know the SID would be to get that information directly from Active Directory. An ISE Admin would typically not have this access, so it would require engaging an AD Admin to find the SID values and provide them ahead of time.

fmunozmiranda commented 1 year ago

@aussietexan , ok thanks for aclaration, it help us, I believe if you do something like this, your tf plan it´s going to work. We first have to create the active_directory resource, then we would have the chance to update it, in this case, add groups, so we only have to add the struct of adgroups to the already created resource in a second apply.

  1. Here is how your tf plan looks at first run

    
    resource "ciscoise_active_directory" "tui-ad" {
    provider = ciscoise.ise31-2
    parameters {
    
    ad_attributes {
    
      #attributes {}
    }
    ad_scopes_names = "Default_Scope"
    adgroups {
    
      #groups {}
    }
    description              = ""
    domain                   = var.domain_name
    name                     = var.join_point_name
    }
    }

resource "ciscoise_active_directory_join_domain_with_all_nodes" "tui-ad" { provider = ciscoise.ise31-2 lifecycle { create_before_destroy = true } parameters { id = ciscoise_active_directory.tui-ad.parameters[0].id additional_data {

  name  = "username"
  value = var.ad_admin_name
}
additional_data {

  name  = "password"
  value = var.ise-password
}

} }

2. Now, we can add to first active_directory resource, the groups, here´s how should look the second apply run without destroy anything, because this is only an update for active_directory resource:
```tf
resource "ciscoise_active_directory" "tui-ad" {
  provider = ciscoise.ise31-2
  parameters {

    ad_attributes {

      #attributes {}
    }
    ad_scopes_names = "Default_Scope"
    adgroups {

      groups {
        name = "domain.com/Users/Domain Computers"
        sid  = "S-1-5-21-3064845550-2309088537-4239914413-515"
        type = "GLOBAL"
       }
    }
    description              = ""
    domain                   = var.domain_name
    name                     = var.join_point_name
  }
}

resource "ciscoise_active_directory_join_domain_with_all_nodes" "tui-ad" {
  provider = ciscoise.ise31-2
  lifecycle {
    create_before_destroy = true
  }
  parameters {
    id = ciscoise_active_directory.tui-ad.parameters[0].id
    additional_data {

      name  = "username"
      value = var.ad_admin_name
    }
    additional_data {

      name  = "password"
      value = var.ise-password
    }
  }
}

If it doesn´t work, update us and pass your test with debug to help you please. Thanks.

aussietexan commented 1 year ago

Hi @fmunozmiranda. I can try that approach and have little doubt that it will work, but using that approach seems to negate the reason and value of using terraform to automate the ISE deployment and configuration. If one has to apply the configuration, then update the code and apply it again, that does not seem to be a reasonable workflow for terraform. If there is not a way to make this workflow work with a single TF module, it seems like it would be better to have a separate module that specifically calls the 'addGroups' API to support the order-of-operations required by ISE. With that, one would have the option of either adding the groups in the initial 'cisco_active_directory' resource (if they already know the SID) or adding them after the join using a query to get the SID and use that captured value.

aussietexan commented 1 year ago

It would also be ideal if the 'add_groups' resource could support the for_each meta argument if possible so one could create a set or list of group name (key), sid (value.sid), and type (value.type) that could be looped through rather than having multiple "groups" blocks. Some customer deployments have 100+ AD groups added to ISE, so creating a variable set or list (or some other method) that could be read in would be much better than having a huge number of those blocks in a single monolithic code.

fmunozmiranda commented 1 year ago

@aussietexan , a terraform resource was added for this. Here's documentation: https://registry.terraform.io/providers/CiscoISE/ciscoise/latest/docs/resources/active_directory_add_groups

Please try it with this, and let us now if it works for you.

aussietexan commented 1 year ago

Hi @fmunozmiranda. I tested the new resource and it works as expected. I was also able to use the data source to query the domain with a filter and use those values in the resource block.

Example code

data "ciscoise_active_directory_get_groups_by_domain_info" "domain-computers" {
  provider = ciscoise.ise31-2
  id       = ciscoise_active_directory.tui-ad.parameters[0].id
  additional_data {

    name  = "domain"
    value = "domain.com"
  }
  additional_data {

    name  = "filter"
    value = "*Domain Computers"
  }
}
resource "ciscoise_active_directory_add_groups" "domain-computers" {
  provider = ciscoise.ise31-2
  parameters {
    adgroups {
      groups {
        name = data.ciscoise_active_directory_get_groups_by_domain_info.domain-computers.item[0].groups[0].name
        sid  = data.ciscoise_active_directory_get_groups_by_domain_info.domain-computers.item[0].groups[0].sid
        type = data.ciscoise_active_directory_get_groups_by_domain_info.domain-computers.item[0].groups[0].type
      }
    }
    description = ""
    domain      = var.domain_name
    name        = var.join_point_name
    id = ciscoise_active_directory.tui-ad.parameters[0].id
  }
}

Just a note on the resource and documentation... the blocks for 'ad_attributes' and 'advanced_settings' are probably not necessary for this 'ciscoise_active_directory_add_groups' resource. Those parameters are related to the 'ciscoise_active_directory' resource so any updates to those parameters would be done there instead of using the 'add_groups' resource.

fmunozmiranda commented 1 year ago

Thanks for infomation @aussietexan