keenauth_attack_protection
The keenauth_attack_protection resource manages the attack-protection settings of the environment: brute force, suspicious-IP throttling, credential stuffing and attack mode, bot protection, breached passwords, sign-up protection, SMS fraud protection and the risk policy.
One object per environment
The attack-protection object exists once per environment and always exists. Declare the resource at most once per provider configuration. Creating the resource reads the current object and writes only what your configuration changes. Destroying it only removes it from state; the environment keeps its protection settings, so a destroy never loosens security silently.
Only what you write is managed
An attribute or group you leave out keeps its current value. Removing an attribute from the configuration keeps its last value. The state holds the effective values, which are the defaults, security floors and plan gates the API applied, so a downgraded plan shows up as a change in the next plan. Lists such as suspicious_ip_throttling.allowlist and sms_protection.allowed_countries are sets, so their order does not matter.
resource "keenauth_attack_protection" "this" {
brute_force = {
max_failures = 10
lock_minutes = 30
}
suspicious_ip_throttling = {
allowlist = ["203.0.113.0/24"]
}
sms_protection = {
allowed_countries = ["DE", "TR"]
daily_cap = 500
}
risk_policy = {
mode = "enforce"
challenge_threshold = 5
block_threshold = 8
}
}
Groups
| Attribute | What it controls |
|---|---|
brute_force |
Per-user lock after failed sign-ins: mode, failures before a lock, counting window, lock duration, user e-mail. |
suspicious_ip_throttling |
Per-IP limits for failed sign-ins and sign-ups, and the CIDR allowlist that is exempt. |
credential_stuffing |
Credential stuffing detection mode and attack mode (automatic start, duration). |
bot_protection |
Bot challenge mode (off, risk_based, always) and provider. |
breached_password |
What happens when a breached password is used at sign-up, on password change and at sign-in. |
signup_protection |
Disposable e-mail, + sub-addresses and the sign-ups per device in 30 days. |
sms_protection |
Countries SMS may go to, daily cap and the conversion breaker. |
risk_policy |
Risk mode, challenge and block thresholds, new-device notification. |
Security floors and plan gates
- Values below a security floor (more than 100 failed attempts before a lock, a lock shorter than 5 minutes, more than 20 sign-ups per IP per hour) are rejected at plan time. The blocking choices of
breached_password.on_signupandon_password_changeare floors too. risk_policy.block_thresholdmust be greater thanrisk_policy.challenge_threshold.risk_policy.mode = "enforce"needs the Startup plan or above; the API answers403 plan_feature_unavailableotherwise.block_thresholdanddaily_caparenullin state while off. Once you set them, the configuration cannot switch them off again; use the dashboard or the management API for that.- Allowlist entries are canonical network addresses such as
203.0.113.0/24. IPv4 prefixes broader than /8 and IPv6 prefixes broader than /32 are rejected.
Safe changes
- An update sends only the changed fields as a JSON merge patch with
If-Match. If someone changed the object after the plan was made, the API answers412and nothing changes. Runplanagain. - A change made in the dashboard shows up in the next
planas drift, andapplyreverts it for the attributes you manage. - Active lockouts and attack mode are operations, not configuration: use the dashboard or the management API (
/v1/attack-protection/lockoutsand/v1/attack-protection/attack-mode) for them.
Import
tofu import keenauth_attack_protection.this attack-protection