mrparkers / terraform-provider-keycloak Goto Github PK
View Code? Open in Web Editor NEWTerraform provider for Keycloak
Home Page: https://registry.terraform.io/providers/mrparkers/keycloak/latest/docs
License: MIT License
Terraform provider for Keycloak
Home Page: https://registry.terraform.io/providers/mrparkers/keycloak/latest/docs
License: MIT License
Hi, thank you for this provider!
We have a realm installation that features quite a lot of different roles and client-roles, and we would love to be able to create them through Terraform.
Is this new resource something you were considering adding?
Some acceptance tests are needed for authenticating against a non-master realm, which was added in #88.
@mrparkers Thank you for providing terraform provider for keycloak.
I would like to use this plugin for my keycloak.
but when I tried to use it, I have 401 Unauthorized error.
I was assuming that my keycloak configuration was wrong. ( I gave admin role to the keycloak client )
but when I tested with keycloak plugin provided from https://github.com/tazjin/terraform-provider-keycloak, it's working properly.
it seems like that tazjin's repo is no longer maintained, I would like to try your plugin.
can you please check if you can give me advise...
** version information **
terraform : v0.11.11
terraform provider keycloak : v1.4.0
keycloak version : 4.7.0
** my test code **
provider "keycloak" {
client_id = "terraform"
client_secret = "xxxxxxx"
url = "https://xxxx.com"
}
resource "keycloak_realm" "iot_sso" {
realm = "iot-sso"
}
** terraform apply error **
* keycloak_realm.iot_sso: error sending GET request to /auth/admin/serverinfo: 401 Unauthorized
** terraform import error **
$ ~/terraform1111 import keycloak_realm.iot_sso iot-sso
keycloak_realm.iot_sso: Importing from ID "iot-sso"...
keycloak_realm.iot_sso: Import complete!
Imported keycloak_realm (ID: iot-sso)
keycloak_realm.iot_sso: Refreshing state... (ID: iot-sso)
Error: keycloak_realm.iot_sso (import id: iot-sso): 1 error(s) occurred:
* import keycloak_realm.iot_sso result: iot-sso: keycloak_realm.iot_sso: error sending GET request to /auth/admin/realms/iot-sso: 401 Unauthorized
Romi
It would be good to provide a resource for managing Identity Providers.
https://www.keycloak.org/docs-api/5.0/rest-api/index.html#_identity_providers_resource
I think I prefer add_to_id_token
over id_token_claim
, as an example.
For example, if you try to create a new realm at the same time as creating the account
client and the account
roles because you need to reference them when you create groups, you'll get a 409 conflict. I don't know a whole bunch about terraform, so this might just be something we have to deal with. Is there a way around this? Like where when a realm is created if clients/roles exist that were created they'll automatically be imported?
Hi,
I am using this version :
ii terraform-provider-keycloak 1.10.0+git20190907.f15366f amd64 Terraform keycloak provider
When I try to set an openid connect client role without any composite role (an empty list), I have got an error:
resource "keycloak_role" "role_yyyy" {
realm_id = "${module.realm_xxxx.id}"
client_id = "${module.openid_client_xxxx_yyyy.id}"
name = "user"
composite_roles = []
}
Plan:
Error: keycloak_role.role_yyyy: composite_roles: attribute supports 1 item as a minimum, config has 0 declared
I would like to be able to set an empty list to be sure of the conformity of my role.
Thank you,
Pierre
Just got burned by a lack of import validation for any ldap protocol mapper. It should check to ensure you're providing the realm, ldap federation ID, and mapper ID, and tests should be added around this as well.
This would allow for Terraform to manage arbitrary execution flows that can then override the default flows on either a client or realm-level; the main benefit being that it would allow for custom authenticators to be used to paper over legacy auth solutions or even to require customers to accept new terms and conditions.
API docs:
// "basic-flow" is the authentication provider id
keycloak_authentication_basic_flow "custom-terms-flow" {
realm_id = "${keycloak_realm.my-realm.id}"
alias = "require-new-terms-and-conditions"
description = "Make customers accept our new T&C"
}
keycloak_authentication_execution "custom-terms-execution" {
flow_id = "${keycloak_authentication_basic_flow.custom-terms-flow.id}"
provider = "terms-and-conditions-authenticator"
config = "?" // this can be an arbitrary map, so maybe it deserves a custom resource
}
I forgot to use omitempty
for the POST body for those properties ๐คฆโโ๏ธ
#106 upgrades the provider to support Keycloak 6.0.1. While I don't believe the provider itself needs to be changed to support each version of Keycloak, it would be nice for the acceptance tests to test against all supported versions to give confidence to the users who are not ready to upgrade yet.
should be "reset credentials"
some validate methods require some communication with the keycloak server, so I have been passing a pointer to the keycloak client in order to do this. instead of this, all validate methods should use the keycloak client as a receiver and take the struct that is being validated as an argument.
If a group that has its members controlled by keycloak_group_memberships
is manually deleted, subsequent plans or applies will fail. It should automatically be removed from state if the group no longer exists.
example that should be fixed: https://github.com/mrparkers/terraform-provider-keycloak/blob/master/provider/keycloak_realm.go#L172
I prefer terms like map
over get
since get
can mean many different things within the context of a provider interacting with a restful API
Provide a data source for retrieving keys of a realm.
The REAST API of Keycloak provides a GET
method for realm keys
Filtering by algorithm and other attributes would be useful.
When trying to run terraform with the keycloak-provider configured inside a docker container, the executable cannot be run.
It appears the released binary of the keycloak-provider is links to the glibc. However, the official terraform image is based on Alpine Linux and therefore uses musclibc.
We made it work that way with previous releases so I'm confident it's only a matter of rebuilding the latest version.
The complete behaviour within the container is :
> /provision # terraform init
Initializing the backend...
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
> /provision # terraform plan
Error: Failed to instantiate provider "keycloak" to obtain schema: fork/exec /root/.terraform.d/plugins/terraform-provider-keycloak_v1.8.0: no such file or directory
> /provision # ls -al /root/.terraform.d/plugins/terraform-provider-keycloak_v1.8.0
-rwxr-xr-x 1 root root 27065137 Jun 12 09:03 /root/.terraform.d/plugins/terraform-provider-keycloak_v1.8.0
> /provision # ldd /root/.terraform.d/plugins/terraform-provider-keycloak_v1.8.0
/lib64/ld-linux-x86-64.so.2 (0x7fb0bab6a000)
libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7fb0bab6a000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fb0bab6a000)
> /provision # /root/.terraform.d/plugins/terraform-provider-keycloak_v1.8.0
/bin/sh: /root/.terraform.d/plugins/terraform-provider-keycloak_v1.8.0: not found
> /provision # ldd /root/.terraform.d/plugins/terraform-provider-keycloak_v1.1.0
ldd: terraform-provider-keycloak_v1.1.0: Not a valid dynamic program
I'm not familiar enough with Go builds so I am unable to provide a fix for this :( but it used to work (last tested with version 1.1.0).
Tagged as "new resource" because I think a separate resource is the best way to do this.
Authoritative:
resource "keycloak_openid_client" "test_client" {
client_id = "test-client"
name = "test-client"
realm_id = "master"
description = "a test client"
access_type = "CONFIDENTIAL"
valid_redirect_uris = [
"http://localhost:8080/callback"
]
}
resource "keycloak_openid_client_scope" "test_client_scope" {
name = "foo1"
realm_id = "master"
description = "test"
consent_screen_text = "hello"
}
resource "keycloak_openid_client_default_client_scopes" "authoritative_scopes" {
realm_id = "master"
client_id = "${keycloak_openid_client.test_client.id}"
default_scopes = [
"profile",
"email",
"${keycloak_openid_client_scope.test_client_scope.name}"
]
}
Non authoritative:
resource "keycloak_openid_client" "test_client" {
client_id = "test-client"
name = "test-client"
realm_id = "master"
description = "a test client"
access_type = "CONFIDENTIAL"
valid_redirect_uris = [
"http://localhost:8080/callback"
]
}
resource "keycloak_openid_client_scope" "test_client_scope" {
name = "foo1"
realm_id = "master"
description = "test"
consent_screen_text = "hello"
}
resource "keycloak_openid_client_default_client_scope" "non_authoritative_scopes" {
realm_id = "master"
client_id = "${keycloak_openid_client.test_client.id}"
default_scope = "${keycloak_openid_client_scope.test_client_scope.name}"
}
thoughts:
Currently, this provider assumes you will be using the master
realm for authentication and configuring Keycloak, but I think it makes sense to want to use other realms for this too, perhaps to limit the scope of a service account to only one realm, or to allow different teams to configure their own realms without being given access to master
.
In particular, I think the provider would have to support:
realm_id
should not be a required attribute on all resourcesSince the diff has to be ignored after initial creation, there is a bug if you go to update the bind_credential after the resource is initially provisioned.
this seems to only happen during acceptance tests (where lots of realms are being created and destroyed), but it's still annoying enough to document it here. a temporary fix was added in #29
In order to read Keycloak generated credentials, provider should support data source on client and user.
This is a reminder for me to add missing docs for the following resources and data sources:
resources:
data sources:
I will try to add these when I have time, and I will happily accept PRs from anyone who is interested in contributing these.
This would grant a specified Keycloak role to each Keycloak user linked with LDAP.
See documentation
It could look like this:
resource "keycloak_ldap_hardcoded_role_mapper" "role_mapper" {
realm_id = "${keycloak_realm.my-realm.id}"
ldap_user_federation_id = "${keycloak_ldap_user_federation.my-ldap.id}"
name = "my-role-mapper"
role = "my-role"
}
Currently it's only possible to use the DEFAULT
or NO_CACHE
cache policies with the provider; all the other cache policies require some user input (e.g., EVICT_DAILY
needs to know the hour and minute to evict).
Currently the scope of a client (ATTENTION: do not do not confuse with Client Scopes / Scope Mapping) can not beconfigured. The default configuration uses Full Scope Allowed=TRUE
. I want to be able to set this to Full Scope Allowed=FALSE
.
The REST API requires to update the client with a clientrepresentation where fullScopeAllowed=false
This would entail adding direct_access_grants_enabled
to keycloak_openid_client
. Most applications should go through the standard flow and should not be able to use the resource owner credentials flow.
Much of the functionality in KeycloakClient
for logging in and refreshing the access token seems to re-implement behavior already implemented in golang.org/x/oauth2 and golang.org/x/oauth2/clientcredentials. This issue includes research into whether those libraries would be sufficient, and refactoring KeycloakClient
to use them if they are. I would be happy to take this on.
This is less a feature request than a mergeability poll, as I'm very much inclined to submit a pull request for this.
My feature would be
When a user is created and initial_password
is set
A call to /users/{user_id}reset-password
is made to initialize a password.
When a user is updated and initial_password
is set
No further call is made
When initial_password
is not set, do as is done now.
Would you accept such a feature ?
Hi there,
whilst looking through the list of community terraform providers, I got surprised a provider for Keycloak was listed. I though the one I've been contributing to and using at work the last couple of years, was the only one around -- obviously not, hoooray! ๐
Have you seen tazjin/terraform-provider-keycloak before? It was initially created by a consultant we hired at work, who's moved on to other projects, but we're still actively using it and expanding it as needed..
Your project looks great! At first glance it looks like you've mapped quite a few more resources than we have, and an actual presence of tests which we have neglected for too long.
Is this provider being actively used in production environments and has proven to be stable? Would you mind if we as maintainers of the other provider, started contributing to this project?
We have a custom user federation SPI that connects to our legacy my_users postgresql database.
In our Custom SPI we have some extra config parameters: jdbc_url, user, ...
We were hoping that we could pass along these extra config parameters through the keycloak_custom_user_federation terraform config.
But it seems that the "keycloak_custom_user_federation" only knows the fields that were defined in CustomUserFederation struct.
Is there a way to make our config work with current implementation?
If not, what would need to be changed, so that custom user federation with extra config parameters would work. Can we work with a config map variable?
I would prefer not to fork this project to extend CustomUserFederation struct with our specific case config fields. I rather create generic solution for all custom federation SPIs.
we would have following config
resource "keycloak_custom_user_federation" "my-user-fed" {
name = "my-user-fed"
realm_id = "${keycloak_realm.test.id}"
enabled = true
priority = "0"
jdbc_url = "jdbc:postgresql://postgres:5432/my_users"
user = "myuser"
password = "mypassword"
cache_policy = "DEFAULT"
}
or perhaps
resource "keycloak_custom_user_federation" "my-user-fed" {
name = "my-user-fed"
realm_id = "${keycloak_realm.test.id}"
enabled = true
priority = "0"
extra_config {
jdbc_url = "jdbc:postgresql://postgres:5432/my_users"
user = "myuser"
password = "mypassword"
}
cache_policy = "DEFAULT"
}
We have a custom oidc identity provider with custom config.
I would like to add this extra config to this terraform keycloak provider.
I do not how to go forward with this.
Do I change the IdentityProvider implementation to change IdentityProviderConfig struct to be just a map[string]interface{} where i do a mapping per field so that the have the correct json key?
for example:
func getOidcIdentityProviderFromData(data *schema.ResourceData) (*keycloak.IdentityProvider, error) {
rec, _ := getIdentityProviderFromData(data)
rec.ProviderId = "oidc"
config := make(map[string]interface{})
if v, ok := data.GetOk("config"); ok {
for key, value := range v.(map[string]interface{}) {
if key == "backchannel_supported" {
config["backchannelSupported"] = keycloak.KeycloakBoolQuoted(value.(bool))
}else if key == "jwks_url" {
config["useJwksUrl"] = keycloak.KeycloakBoolQuoted(true)
config["jwksUrl"] = value.(string)
}else if .... {
.....
}else{
config[key] = value.(string) // all extra config
}
}
}
rec.Config = config
Or do I create a CustomIdentityProvider struct which has the same methods as IdentityProvider, but where all config parameters are part of a map[string]interface{}
I still would have to map every field like in the solution above.
Or do you have another suggestion?
this line can fail if the ldap user federation provider has cache disabled, because the Keycloak API won't return this field
There's currently a consent_screen_text
field on the client scope resource, but no way to disable text entirely (this is configurable on a client basis as well).
For the API, it looks like this requires setting attributes.display.on.consent.screen
.
It would be great to manage the email options for a realm; this is needed for "forgot password" emails and email verification.
Another missing field is offline_session_max_lifespan_enabled
. It controls whether offline_session_max_lifespan
is enforced:
if you enable the option Offline Session Max Limited, then the offline token expires after 60 days regardless of using the offline token for a refresh token action (this value, Offline Session Max lifespan, can also be changed in the administration console in the Tokens tab under Realm Settings)
Admin UI:
There are a number of these so there would probably resources for each rather than a shared mega-resource.
Example Terraform config for adding a hard-coded claim:
resource "hard_coded_claim" "my-foo-claim" {
protocol = "openid-connect"
name = "foo-claim"
claim_name = "foo"
claim_string_value = "bar" // mutually exclusive long_value, int_value, bool_value fields
add_to_access_token = true
add_to_id_token = false
}
for some reason, two different protocol mappers can't have the same name. example tf config that fails with a 409 conflict:
resource "keycloak_realm" "test" {
realm = "test"
enabled = true
display_name = "foo"
account_theme = "base"
access_code_lifespan = "30m"
}
resource "keycloak_openid_client_scope" "test_client_scope" {
name = "foo1"
realm_id = "${keycloak_realm.test.id}"
description = "test"
consent_screen_text = "hello"
}
// one of the two resources below will succeed, one will fail
resource "keycloak_openid_group_membership_protocol_mapper" "map_group_memberships_client_scope" {
name = "foo"
realm_id = "${keycloak_realm.test.id}"
client_scope_id = "${keycloak_openid_client_scope.test_client_scope.id}"
claim_name = "bar2"
}
resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_attributes_client_scope" {
name = "foo"
realm_id = "${keycloak_realm.test.id}"
client_scope_id = "${keycloak_openid_client_scope.test_client_scope.id}"
user_attribute = "foo2"
claim_name = "bar2"
}
validation should be added to ensure that you can't create a protocol mapper with the same name as another one, and give a good error message instead of "409 conflict"
this definitely seems like it should be one word: https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
there are several places in the code where this could be changed.
Hello
Thanks for the great work you did on Terraforming Keycloak!!!
It's too bad to have 2 providers covering different parts of Keycloak instead of one with better coverage...
Is there a reason why you didn't go with https://github.com/tazjin/terraform-provider-keycloak?
It seems to be existing since a moment now...
Cedric
I think this code should be returning err
rather than nil
. As-is, if there's an error removing a user from a group nothing will happen.
In order to configure the roles available to the service account retrieved on behalf of this client...
See documentation.
service_accounts_enabled
has to be enabled:
resource "keycloak_openid_client" "my-client" {
realm_id = "${keycloak_realm.my-realm.id}"
client_id = "my-client"
service_accounts_enabled = true
...
}
This would grant a specified Keycloak group to each Keycloak user linked with LDAP.
See documentation
It could look like this:
resource "keycloak_ldap_hardcoded_group_mapper" "group_mapper" {
realm_id = "${keycloak_realm.my-realm.id}"
ldap_user_federation_id = "${keycloak_ldap_user_federation.my-ldap.id}"
name = "my-group-mapper"
group = "my-group"
}
=
. example that needs to be fixedIt is not possible to download the releases as a machine user without github credentials. Would it be possible to also upload the artifacts to an official S3 bucket where the plugin can be downloaded freely without credentials. This is necessary for building docker images in our CI/CD system that require unauthenticated access to these artifacts.
Discussion started in #143.
For mapping roles to a service account, it makes sense to make to have a data source to get the ID of that service account, and use a resource like keycloak_user_roles
to map roles to it. It might look something like this:
resource "keycloak_openid_client" "client" {
realm_id = "${keycloak_realm.realm.id}"
client_id = "client"
name = "client"
enabled = true
access_type = "CONFIDENTIAL"
client_secret = "secret"
service_accounts_enabled = true
}
data "keycloak_service_account_user" "client_service_account" {
client_id = "${keycloak_openid_client.client.id}"
}
resource "keycloak_role" "role" {
realm_id = "${keycloak_realm.realm.id}"
name = "my-role"
}
resource "keycloak_user_roles" "client_service_account_roles" {
realm_id = "${keycloak_realm.realm.id}"
user_id = "${data.keycloak_service_account_user.client_service_account.id}"
roles = [
"${keycloak_role.role.id}"
]
}
thoughts? cc @rlewan @camelpunch
AFAICT, there is no way to specify default groups at the moment. This would be fairly easy to implement, since it's a really basic resource. The relevant endpoints are:
GET /{realm}/default-groups (returns a list of all default groups)
PUT /{realm}/default-groups/{groupId} (add a group to the list of default groups)
DELETE /{realm}/default-groups/{groupId} (delete a group from the list of default groups)
The first way that comes to mind for how this could be implemented is having a very basic resource for each default group that simply maps a realm id to a group id. This maps very well to the keycloak API. The HCL would look something look this:
resource "keycloak_group" "example_group" {
realm_id = "${keycloak_realm.realm.id}"
name = "example-group"
}
resource "keycloak_default_group" "example_group" {
realm_id = "${keycloak_realm.realm.id}"
group_id = "${keycloak_group.example_group.id}"
}
We could also have a default groups property on realms, or have a default groups resource, or have a default group property on groups, but I don't think those solutions map very well to the API. Additionally, we could specify it on the realm, but then we get into a scenario where if a realm references groups that need to be created after the realm is then there's a potential deadlock.
I would be happy to take a crack at adding this feature.
Currently the realease candidate (rc1) of the module terraform is referenced at go.mod
=> upgrade to release version
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.