Skip to main content

Enable RADIUS-Based MFA for Directory Service

Overview

This check validates whether your AWS Directory Service directories have RADIUS-based multi-factor authentication (MFA) enabled. When enabled, users must provide both their password and a one-time code from an MFA device to authenticate, significantly strengthening access security.

Risk

Without MFA enabled, user authentication relies solely on passwords. This creates vulnerability to:

  • Credential theft through phishing attacks
  • Password spraying and brute-force attacks
  • Unauthorized access if passwords are compromised or leaked
  • Lateral movement and privilege escalation within connected AWS services

Remediation Steps

Prerequisites

  • A working RADIUS server (such as Microsoft NPS, FreeRADIUS, or a commercial MFA solution like Duo, Okta, or RSA SecurID)
  • Network connectivity between your Directory Service VPC and the RADIUS server
  • The shared secret configured on your RADIUS server
  • AWS Console access with permissions to modify Directory Service settings
Required IAM permissions

Your IAM user or role needs the following permissions:

  • ds:EnableRadius
  • ds:DescribeDirectories
  • ds:DisableRadius (for troubleshooting/updates)
RADIUS server network requirements

Before enabling RADIUS MFA, ensure:

  1. Your RADIUS server is reachable from the Directory Service VPC
  2. Security groups allow outbound traffic on the RADIUS port (typically UDP 1812)
  3. The RADIUS server is configured to accept connections from the Directory Service domain controllers
  4. You have tested RADIUS connectivity independently

AWS Console Method

  1. Open the AWS Directory Service console
  2. In the navigation pane, choose Directories
  3. Click on the Directory ID of your target directory
  4. Select the Networking & security tab
  5. Scroll down to the Multi-factor authentication section
  6. Click Actions, then select Enable
  7. Enter your RADIUS configuration:
    • RADIUS server IP address(es): Enter one or more RADIUS server IPs or DNS names
    • Port: Usually 1812 (the standard RADIUS authentication port)
    • Shared secret code: The secret configured on your RADIUS server
    • Confirm shared secret code: Re-enter the shared secret
    • Protocol: Select the authentication protocol your RADIUS server uses (typically MS-CHAPv2)
    • Server timeout: How long to wait for a response (10-30 seconds recommended)
    • Max retries: Number of retry attempts (3 is typical)
  8. Click Enable

The RADIUS status will show Creating initially. Wait for it to change to Completed.

AWS CLI (optional)

Enable RADIUS MFA via CLI

First, identify your directory ID:

aws ds describe-directories \
--region us-east-1 \
--query "DirectoryDescriptions[*].[DirectoryId,Name,Type]" \
--output table

Enable RADIUS MFA:

aws ds enable-radius \
--directory-id d-1234567890 \
--radius-settings '{
"RadiusServers": ["radius.example.com"],
"RadiusPort": 1812,
"RadiusTimeout": 10,
"RadiusRetries": 3,
"SharedSecret": "YourSharedSecretHere",
"AuthenticationProtocol": "MS-CHAPv2"
}' \
--region us-east-1

Replace the following placeholders:

  • d-1234567890: Your directory ID
  • radius.example.com: Your RADIUS server IP or hostname
  • YourSharedSecretHere: The shared secret configured on your RADIUS server

RadiusSettings parameters

ParameterDescriptionConstraints
RadiusServersIP addresses or FQDNs of RADIUS endpointsList of strings
RadiusPortRADIUS authentication port1025-65535 (default: 1812)
RadiusTimeoutSeconds to wait for response1-50
RadiusRetriesMaximum retry attempts0-10
SharedSecretShared secret for RADIUS authentication8-512 characters
AuthenticationProtocolProtocol usedPAP, CHAP, MS-CHAPv1, or MS-CHAPv2
CloudFormation (optional)

AWS CloudFormation does not natively support configuring RADIUS MFA settings for Directory Service. You must use one of these alternatives:

Option 1: AWS CLI in a Custom Resource

AWSTemplateFormatVersion: '2010-09-09'
Description: Enable RADIUS MFA for AWS Directory Service using Custom Resource

Parameters:
DirectoryId:
Type: String
Description: The ID of the directory (e.g., d-1234567890)
AllowedPattern: ^d-[0-9a-f]{10}$
RadiusServer:
Type: String
Description: IP address or FQDN of your RADIUS server
RadiusSharedSecret:
Type: String
NoEcho: true
Description: Shared secret for RADIUS authentication
MinLength: 8

Resources:
EnableRadiusFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: EnableDirectoryServiceRadius
Runtime: python3.11
Handler: index.handler
Timeout: 60
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
import boto3
import cfnresponse

def handler(event, context):
ds = boto3.client('ds')
directory_id = event['ResourceProperties']['DirectoryId']

if event['RequestType'] == 'Delete':
try:
ds.disable_radius(DirectoryId=directory_id)
except Exception as e:
print(f"Error disabling RADIUS: {e}")
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
return

try:
ds.enable_radius(
DirectoryId=directory_id,
RadiusSettings={
'RadiusServers': [event['ResourceProperties']['RadiusServer']],
'RadiusPort': 1812,
'RadiusTimeout': 10,
'RadiusRetries': 3,
'SharedSecret': event['ResourceProperties']['SharedSecret'],
'AuthenticationProtocol': 'MS-CHAPv2'
}
)
cfnresponse.send(event, context, cfnresponse.SUCCESS, {'Status': 'Enabled'})
except Exception as e:
cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)})

LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: DirectoryServiceRadius
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ds:EnableRadius
- ds:DisableRadius
Resource: !Sub arn:aws:ds:${AWS::Region}:${AWS::AccountId}:directory/${DirectoryId}

EnableRadiusCustomResource:
Type: Custom::EnableRadius
Properties:
ServiceToken: !GetAtt EnableRadiusFunction.Arn
DirectoryId: !Ref DirectoryId
RadiusServer: !Ref RadiusServer
SharedSecret: !Ref RadiusSharedSecret

Option 2: Post-deployment CLI command

After deploying your directory via CloudFormation, run the aws ds enable-radius command separately as shown in the CLI section above.

Terraform (optional)
variable "directory_id" {
description = "The ID of the AWS Directory Service directory"
type = string
# Example: d-1234567890
}

variable "radius_servers" {
description = "List of RADIUS server IP addresses or FQDNs"
type = list(string)
}

variable "radius_shared_secret" {
description = "Shared secret for RADIUS authentication"
type = string
sensitive = true
}

variable "radius_port" {
description = "Port on which RADIUS server is listening"
type = number
default = 1812
}

variable "radius_timeout" {
description = "Timeout in seconds for RADIUS requests"
type = number
default = 10
}

variable "radius_retries" {
description = "Number of retries for RADIUS requests"
type = number
default = 3
}

variable "authentication_protocol" {
description = "RADIUS authentication protocol"
type = string
default = "MS-CHAPv2"
validation {
condition = contains(["PAP", "CHAP", "MS-CHAPv1", "MS-CHAPv2"], var.authentication_protocol)
error_message = "Authentication protocol must be one of: PAP, CHAP, MS-CHAPv1, MS-CHAPv2."
}
}

resource "aws_directory_service_radius_settings" "mfa" {
directory_id = var.directory_id

radius_servers = var.radius_servers
radius_port = var.radius_port
radius_timeout = var.radius_timeout
radius_retries = var.radius_retries
shared_secret = var.radius_shared_secret

authentication_protocol = var.authentication_protocol
}

output "radius_status" {
description = "Status of RADIUS MFA configuration"
value = aws_directory_service_radius_settings.mfa.id
}

Apply the configuration:

terraform init
terraform apply \
-var="directory_id=d-1234567890" \
-var='radius_servers=["radius.example.com"]' \
-var="radius_shared_secret=YourSharedSecretHere"

Verification

After enabling RADIUS MFA:

  1. Return to the Networking & security tab of your directory
  2. Check that the Multi-factor authentication status shows Completed
  3. Test by logging into a service that uses the directory (such as WorkSpaces or an AD-joined EC2 instance)
  4. Verify that users are prompted for their MFA token after entering their password
CLI verification commands

Check RADIUS MFA status:

aws ds describe-directories \
--directory-id d-1234567890 \
--region us-east-1 \
--query "DirectoryDescriptions[0].RadiusSettings"

The output should show your RADIUS configuration with RadiusStatus as Completed.

Check overall directory status:

aws ds describe-directories \
--directory-id d-1234567890 \
--region us-east-1 \
--query "DirectoryDescriptions[0].{DirectoryId:DirectoryId,Name:Name,RadiusStatus:RadiusStatus}"
Troubleshooting RADIUS issues

If RADIUS status shows Failed:

  1. Verify network connectivity: Ensure the Directory Service domain controllers can reach your RADIUS server on the specified port
  2. Check security groups: Confirm outbound UDP traffic to the RADIUS port is allowed
  3. Validate shared secret: The shared secret must match exactly on both sides
  4. Test RADIUS server: Use radtest or a similar tool to verify your RADIUS server is responding
  5. Check RADIUS server logs: Look for authentication attempts from the Directory Service IP addresses
  6. Protocol mismatch: Ensure the authentication protocol matches what your RADIUS server expects

To disable and retry:

aws ds disable-radius \
--directory-id d-1234567890 \
--region us-east-1

Then re-enable with corrected settings.

Additional Resources

Notes

  • Supported directory types: RADIUS MFA is available for AWS Managed Microsoft AD and AD Connector. Simple AD does not support RADIUS MFA.
  • High availability: Consider configuring multiple RADIUS servers for redundancy. AWS Directory Service will try each server in order.
  • User experience: After enabling MFA, all users authenticating through the directory will need MFA tokens. Ensure users are enrolled with your MFA provider before enabling.
  • Service interruption: Enabling MFA takes effect immediately. Plan the rollout to avoid disrupting users.
  • Fallback behavior: If RADIUS servers are unreachable, authentication will fail. This is a security feature but may cause access issues during RADIUS outages.
  • Testing: Test with a small group of users before organization-wide rollout.