Skip to content

Commit

Permalink
Add password-policy module (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
posquit0 authored Sep 1, 2024
1 parent aac6ee3 commit f1ad727
Show file tree
Hide file tree
Showing 9 changed files with 573 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .github/labeler.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
- any-glob-to-any-file:
- modules/organization/**/*

":floppy_disk: password-policy":
- changed-files:
- any-glob-to-any-file:
- modules/password-policy/**/*

":floppy_disk: user":
- changed-files:
- any-glob-to-any-file:
Expand Down
3 changes: 3 additions & 0 deletions .github/labels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
- color: "fbca04"
description: "This issue or pull request is related to organization module."
name: ":floppy_disk: organization"
- color: "fbca04"
description: "This issue or pull request is related to password-policy module."
name: ":floppy_disk: password-policy"
- color: "fbca04"
description: "This issue or pull request is related to user module."
name: ":floppy_disk: user"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Terraform module to manage all of things on Okta organization.
- [group](./modules/group/)
- [group-rule](./modules/group-rule/)
- [organization](./modules/organization/)
- [password-policy](./modules/password-policy/)
- [user](./modules/user/)


Expand Down
68 changes: 68 additions & 0 deletions modules/password-policy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# password-policy

This module creates following resources.

- `okta_policy_password` (optional)
- `okta_policy_password_default` (optional)
- `okta_policy_rule_password` (optional)

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.8 |
| <a name="requirement_okta"></a> [okta](#requirement\_okta) | >= 4.8 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_okta"></a> [okta](#provider\_okta) | 4.8.1 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [okta_policy_password.this](https://registry.terraform.io/providers/okta/okta/latest/docs/resources/policy_password) | resource |
| [okta_policy_password_default.this](https://registry.terraform.io/providers/okta/okta/latest/docs/resources/policy_password_default) | resource |
| [okta_policy_rule_password.this](https://registry.terraform.io/providers/okta/okta/latest/docs/resources/policy_rule_password) | resource |
| [okta_group.this](https://registry.terraform.io/providers/okta/okta/latest/docs/data-sources/group) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_name"></a> [name](#input\_name) | (Required) A name of the Okta Password Policy. Use `default` to manage the default password policy. | `string` | n/a | yes |
| <a name="input_authentication_provider"></a> [authentication\_provider](#input\_authentication\_provider) | (Optional) The authentication provider which the Okta Password Policy applies to. Valid values are `OKTA`, `LDAP`, `ACTIVE_DIRECTORY`. Defaults to `OKTA`. | `string` | `"OKTA"` | no |
| <a name="input_complexity"></a> [complexity](#input\_complexity) | (Optional) A configuration for password complexity requirements of the Okta Password Policy. `complexity` block as defined below.<br> (Optional) `min_length` - Minimum password length. Defaults to `8`.<br> (Optional) `lowercase_required` - If a password must contain at least one lower case letter. Defaults to `true`.<br> (Optional) `uppercase_required` - If a password must contain at least one upper case letter. Defaults to `true`.<br> (Optional) `number_required` - If a password must contain at least one number. Defaults to `true`.<br> (Optional) `symbol_required` - If a password must contain at least one symbol (!@#$%^&*). Defaults to `false`.<br> (Optional) `first_name_restricted` - If a password must not contain the user's first name. Defaults to `false`.<br> (Optional) `last_name_restricted` - If a password must not contain the user's last name. Defaults to `false`.<br> (Optional) `username_restricted` - If a password must not contain the user's username. Defaults to `true`.<br> (Optional) `common_password_restricted` - Whether to restrict passwords against common password dictionary. Defaults to `true`.<br> (Optional) `reuse_restriction_count` - The number of distinct passwords that must be created before they can be reused. The value of `0` means no restriction. Defaults to `0`. | <pre>object({<br> min_length = optional(number, 8)<br><br> lowercase_required = optional(bool, true)<br> uppercase_required = optional(bool, true)<br> number_required = optional(bool, true)<br> symbol_required = optional(bool, false)<br><br> first_name_restricted = optional(bool, false)<br> last_name_restricted = optional(bool, false)<br> username_restricted = optional(bool, true)<br> common_password_restricted = optional(bool, true)<br><br> reuse_restriction_count = optional(number, 0)<br> })</pre> | `{}` | no |
| <a name="input_description"></a> [description](#input\_description) | (Optional) A description of the Okta Password Policy. Only used when `name` is not `default`. | `string` | `"Managed by Terraform."` | no |
| <a name="input_enabled"></a> [enabled](#input\_enabled) | (Optional) Whether to enable the Okta Password Policy. Defaults to `true`. Only used when `name` is not `default`. | `bool` | `true` | no |
| <a name="input_expiration"></a> [expiration](#input\_expiration) | (Optional) A configuration for password expiration of the Okta Password Policy. `expiration` block as defined below.<br> (Optional) `max_age_days` - The number of days before a password expires. The value of `0` means no expiration. Defaults to `0`.<br> (Optional) `min_age_minutes` - The minimum number of minutes that must pass before a password can be changed. The value of `0` means no limit. Defaults to `0<br> (Optional) `remind\_before\_days` - The number of days before a password expires to remind the user. The value of `0` means no reminder. Defaults to `0`.<br>` | <pre>object({<br> max_age_days = optional(number, 0)<br> min_age_minutes = optional(number, 0)<br> remind_before_days = optional(number, 0)<br> })</pre> | `{}` | no |
| <a name="input_groups"></a> [groups](#input\_groups) | (Optional) A set of group IDs to assign the Okta Password Policy to. | `set(string)` | `[]` | no |
| <a name="input_lockout"></a> [lockout](#input\_lockout) | (Optional) A configuration for password lock-out of the Okta Password Policy. `lockout` block as defined below.<br> (Optional) `max_attempts` - Maximum number of unsuccessful login attempts before a user is locked out. The value of `0` means no limit. Defaults to `10`.<br> (Optional) `duration` - Number of minutes before a locked account is unlocked. The value of `0` means no limit. Defaults to `60`.<br> (Optional) `show_failures` - Whether to inform a user when their account is locked. Defaults to `false`.<br> (Optional) `notification_channels` - A set of notification channels to use to notify a user when their account has been locked. Valid values are `EMAIL`, `SMS`, `PUSH`. Defaults to `EMAIL`. | <pre>object({<br> max_attempts = optional(number, 10)<br> duration = optional(number, 60)<br> show_failures = optional(bool, false)<br> notification_channels = optional(set(string), ["EMAIL"])<br> })</pre> | `{}` | no |
| <a name="input_priority"></a> [priority](#input\_priority) | (Optional) A priority of the Okta Password Policy. Only used when `name` is not `default`. | `number` | `null` | no |
| <a name="input_recovery"></a> [recovery](#input\_recovery) | (Optional) A configuration for password recovery of the Okta Password Policy. `recovery` block as defined below.<br> (Optional) `call` - A configuration for password recovery call. `call` block as defined below.<br> (Optional) `enabled` - Whether to enable password recovery call. Defaults to `false`.<br> (Optional) `email` - A configuration for password recovery email. `email` block as defined below.<br> (Optional) `enabled` - Whether to enable password recovery email. Defaults to `true`.<br> (Optional) `token_ttl` - Lifetime in minutes of the recovery email token. Defaults to `60`.<br> (Optional) `question` - A configuration for password recovery question. `question` block as defined below.<br> (Optional) `enabled` - Whether to enable password recovery question. Defaults to `false`.<br> (Optional) `min_answer_length` - Minimum length of the password recovery question answer. Defaults to `4`.<br> (Optional) `sms` - A configuration for password recovery sms. `sms` block as defined below.<br> (Optional) `enabled` - Whether to enable password recovery sms. Defaults to `false`. | <pre>object({<br> call = optional(object({<br> enabled = optional(bool, false)<br> }), {})<br> email = optional(object({<br> enabled = optional(bool, true)<br> token_ttl = optional(number, 60)<br> }), {})<br> question = optional(object({<br> enabled = optional(bool, false)<br> min_answer_length = optional(number, 4)<br> }), {})<br> sms = optional(object({<br> enabled = optional(bool, false)<br> }), {})<br> })</pre> | `{}` | no |
| <a name="input_rules"></a> [rules](#input\_rules) | (Optional) A configuration for rules of the Okta Password Policy. Each item of `rules` block as defined below.<br> (Required) `name` - A name of the password policy rule.<br> (Optional) `priority` - A priority of the password policy rule. To avoid an endless diff situation an error is thrown if an invalid property is provided. The Okta API defaults to the last (lowest) if not provided.<br> (Optional) `enabled` - Whether to enable password policy rule. Defaults to `true`.<br> (Optional) `condition` - A condition of the password policy rule. `condition` block as defined below.<br> (Optional) `excluded_users` - A set of user IDs to exclude.<br> (Optional) `network` - A configuration for network condition. `network` block as defined below.<br> (Optional) `excluded_zones` - A set of zone IDs to exclude.<br> (Optional) `included_zones` - A set of zone IDs to include.<br> (Optional) `allow_password_change` - Whether to allow users to change their password. Defaults to `true`.<br> (Optional) `allow_password_reset` - Whether to allow users to reset their password. Defaults to `true`.<br> (Optional) `allow_password_unlock` - Whether to allow users to unlock. Defaults to `false`. | <pre>list(object({<br> name = string<br> priority = optional(number)<br> enabled = optional(bool, true)<br><br> condition = optional(object({<br> excluded_users = optional(set(string), [])<br> network = optional(object({<br> excluded_zones = optional(set(string), [])<br> included_zones = optional(set(string), [])<br> }), {})<br> }), {})<br><br> allow_password_change = optional(bool, true)<br> allow_password_reset = optional(bool, true)<br> allow_password_unlock = optional(bool, false)<br> }))</pre> | `[]` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_authentication_provider"></a> [authentication\_provider](#output\_authentication\_provider) | The authentication provider which the Okta Password Policy applies to. |
| <a name="output_complexity"></a> [complexity](#output\_complexity) | The complexity requirements of the Okta Password Policy. |
| <a name="output_description"></a> [description](#output\_description) | The description of the Okta Password Policy. |
| <a name="output_enabled"></a> [enabled](#output\_enabled) | Whether the Okta Password Policy is enabled. |
| <a name="output_expiration"></a> [expiration](#output\_expiration) | The configuration for password expiration of the Okta Password Policy. |
| <a name="output_groups"></a> [groups](#output\_groups) | The information for the assigned groups of the Okta Password Policy. |
| <a name="output_id"></a> [id](#output\_id) | The ID of the Okta Password Policy. |
| <a name="output_lockout"></a> [lockout](#output\_lockout) | The configuration for password lock-out of the Okta Password Policy. |
| <a name="output_name"></a> [name](#output\_name) | The name of the Okta Password Policy. |
| <a name="output_priority"></a> [priority](#output\_priority) | The priority of the Okta Password Policy. |
| <a name="output_recovery"></a> [recovery](#output\_recovery) | The configuration for password recovery of the Okta Password Policy. |
| <a name="output_rules"></a> [rules](#output\_rules) | The configuration for rules of the Okta Password Policy. |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
126 changes: 126 additions & 0 deletions modules/password-policy/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
locals {
is_default = var.name == "default"

policy = (local.is_default
? merge(okta_policy_password_default.this[0], {
auth_provider = okta_policy_password_default.this[0].default_auth_provider
})
: okta_policy_password.this[0]
)
}


###################################################
# Okta Password Policy
###################################################

# TODO:
# `skip_unlock` (Boolean) When an Active Directory user is locked out of Okta, the Okta unlock operation should also attempt to unlock the user's Windows account. Default: false
resource "okta_policy_password" "this" {
count = local.is_default ? 0 : 1

name = var.name
description = var.description
status = var.enabled ? "ACTIVE" : "INACTIVE"

auth_provider = var.authentication_provider
priority = var.priority
groups_included = var.groups


## Complexity Requirements
password_min_length = var.complexity.min_length

password_min_lowercase = var.complexity.lowercase_required ? 1 : 0
password_min_uppercase = var.complexity.uppercase_required ? 1 : 0
password_min_number = var.complexity.number_required ? 1 : 0
password_min_symbol = var.complexity.symbol_required ? 1 : 0

password_exclude_first_name = var.complexity.first_name_restricted
password_exclude_last_name = var.complexity.last_name_restricted
password_exclude_username = var.complexity.username_restricted
password_dictionary_lookup = var.complexity.common_password_restricted

password_history_count = var.complexity.reuse_restriction_count


## Expiration
password_max_age_days = var.expiration.max_age_days
password_min_age_minutes = var.expiration.min_age_minutes
password_expire_warn_days = var.expiration.remind_before_days


## Lock-out
password_max_lockout_attempts = var.lockout.max_attempts
password_auto_unlock_minutes = var.lockout.duration
password_show_lockout_failures = var.lockout.show_failures
password_lockout_notification_channels = var.lockout.notification_channels


## Recovery
call_recovery = var.recovery.call.enabled ? "ACTIVE" : "INACTIVE"

email_recovery = var.recovery.email.enabled ? "ACTIVE" : "INACTIVE"
recovery_email_token = var.recovery.email.token_ttl

question_recovery = var.recovery.question.enabled ? "ACTIVE" : "INACTIVE"
question_min_length = var.recovery.question.min_answer_length

sms_recovery = var.recovery.sms.enabled ? "ACTIVE" : "INACTIVE"
}

resource "okta_policy_password_default" "this" {
count = local.is_default ? 1 : 0


## Complexity Requirements
password_min_length = var.complexity.min_length

password_min_lowercase = var.complexity.lowercase_required ? 1 : 0
password_min_uppercase = var.complexity.uppercase_required ? 1 : 0
password_min_number = var.complexity.number_required ? 1 : 0
password_min_symbol = var.complexity.symbol_required ? 1 : 0

password_exclude_first_name = var.complexity.first_name_restricted
password_exclude_last_name = var.complexity.last_name_restricted
password_exclude_username = var.complexity.username_restricted
password_dictionary_lookup = var.complexity.common_password_restricted

password_history_count = var.complexity.reuse_restriction_count


## Expiration
password_max_age_days = var.expiration.max_age_days
password_min_age_minutes = var.expiration.min_age_minutes
password_expire_warn_days = var.expiration.remind_before_days


## Lock-out
password_max_lockout_attempts = var.lockout.max_attempts
password_auto_unlock_minutes = var.lockout.duration
password_show_lockout_failures = var.lockout.show_failures
password_lockout_notification_channels = var.lockout.notification_channels


## Recovery
call_recovery = var.recovery.call.enabled ? "ACTIVE" : "INACTIVE"

email_recovery = var.recovery.email.enabled ? "ACTIVE" : "INACTIVE"
recovery_email_token = var.recovery.email.token_ttl

question_recovery = var.recovery.question.enabled ? "ACTIVE" : "INACTIVE"
question_min_length = var.recovery.question.min_answer_length

sms_recovery = var.recovery.sms.enabled ? "ACTIVE" : "INACTIVE"
}


###################################################
# Okta Groups for Password Policy
###################################################

data "okta_group" "this" {
for_each = toset(var.groups)

id = each.value
}
Loading

0 comments on commit f1ad727

Please sign in to comment.