aws-cis-controls-assessment 1.1.3__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. aws_cis_assessment/__init__.py +4 -4
  2. aws_cis_assessment/config/rules/cis_controls_ig1.yaml +365 -2
  3. aws_cis_assessment/controls/ig1/control_access_analyzer.py +198 -0
  4. aws_cis_assessment/controls/ig1/control_access_asset_mgmt.py +360 -0
  5. aws_cis_assessment/controls/ig1/control_access_control.py +323 -0
  6. aws_cis_assessment/controls/ig1/control_backup_security.py +579 -0
  7. aws_cis_assessment/controls/ig1/control_cloudfront_logging.py +215 -0
  8. aws_cis_assessment/controls/ig1/control_configuration_mgmt.py +407 -0
  9. aws_cis_assessment/controls/ig1/control_data_classification.py +255 -0
  10. aws_cis_assessment/controls/ig1/control_dynamodb_encryption.py +279 -0
  11. aws_cis_assessment/controls/ig1/control_ebs_encryption.py +177 -0
  12. aws_cis_assessment/controls/ig1/control_efs_encryption.py +243 -0
  13. aws_cis_assessment/controls/ig1/control_elb_logging.py +195 -0
  14. aws_cis_assessment/controls/ig1/control_guardduty.py +156 -0
  15. aws_cis_assessment/controls/ig1/control_inspector.py +184 -0
  16. aws_cis_assessment/controls/ig1/control_inventory.py +511 -0
  17. aws_cis_assessment/controls/ig1/control_macie.py +165 -0
  18. aws_cis_assessment/controls/ig1/control_messaging_encryption.py +419 -0
  19. aws_cis_assessment/controls/ig1/control_mfa.py +485 -0
  20. aws_cis_assessment/controls/ig1/control_network_security.py +194 -619
  21. aws_cis_assessment/controls/ig1/control_patch_management.py +626 -0
  22. aws_cis_assessment/controls/ig1/control_rds_encryption.py +228 -0
  23. aws_cis_assessment/controls/ig1/control_s3_encryption.py +383 -0
  24. aws_cis_assessment/controls/ig1/control_tls_ssl.py +556 -0
  25. aws_cis_assessment/controls/ig1/control_version_mgmt.py +329 -0
  26. aws_cis_assessment/controls/ig1/control_vpc_flow_logs.py +205 -0
  27. aws_cis_assessment/controls/ig1/control_waf_logging.py +226 -0
  28. aws_cis_assessment/core/models.py +20 -1
  29. aws_cis_assessment/core/scoring_engine.py +98 -1
  30. aws_cis_assessment/reporters/base_reporter.py +31 -1
  31. aws_cis_assessment/reporters/html_reporter.py +172 -11
  32. aws_cis_controls_assessment-1.2.0.dist-info/METADATA +320 -0
  33. {aws_cis_controls_assessment-1.1.3.dist-info → aws_cis_controls_assessment-1.2.0.dist-info}/RECORD +39 -15
  34. docs/developer-guide.md +204 -5
  35. docs/user-guide.md +137 -4
  36. aws_cis_controls_assessment-1.1.3.dist-info/METADATA +0 -404
  37. {aws_cis_controls_assessment-1.1.3.dist-info → aws_cis_controls_assessment-1.2.0.dist-info}/WHEEL +0 -0
  38. {aws_cis_controls_assessment-1.1.3.dist-info → aws_cis_controls_assessment-1.2.0.dist-info}/entry_points.txt +0 -0
  39. {aws_cis_controls_assessment-1.1.3.dist-info → aws_cis_controls_assessment-1.2.0.dist-info}/licenses/LICENSE +0 -0
  40. {aws_cis_controls_assessment-1.1.3.dist-info → aws_cis_controls_assessment-1.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,485 @@
1
+ """
2
+ CIS Control 2.6, 2.7, 2.15 - Multi-Factor Authentication Controls
3
+ Ensures MFA is enabled for administrative access and critical services.
4
+ """
5
+
6
+ import logging
7
+ from typing import List, Dict, Any
8
+ from botocore.exceptions import ClientError
9
+
10
+ from aws_cis_assessment.controls.base_control import BaseConfigRuleAssessment
11
+ from aws_cis_assessment.core.models import ComplianceResult, ComplianceStatus
12
+ from aws_cis_assessment.core.aws_client_factory import AWSClientFactory
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class IAMAdminMFARequiredAssessment(BaseConfigRuleAssessment):
18
+ """
19
+ CIS Control 2.6 - Establish an Access Granting Process
20
+ AWS Config Rule: iam-admin-mfa-required
21
+
22
+ Ensures IAM users with administrative privileges have MFA enabled.
23
+ """
24
+
25
+ def __init__(self):
26
+ super().__init__(
27
+ rule_name="iam-admin-mfa-required",
28
+ control_id="2.6",
29
+ resource_types=["AWS::IAM::User"]
30
+ )
31
+
32
+ def _get_resources(self, aws_factory: AWSClientFactory, resource_type: str, region: str) -> List[Dict[str, Any]]:
33
+ """Get all IAM users and check for admin privileges and MFA."""
34
+ if resource_type != "AWS::IAM::User":
35
+ return []
36
+
37
+ # IAM is global, only check in us-east-1
38
+ if region != 'us-east-1':
39
+ return []
40
+
41
+ try:
42
+ iam_client = aws_factory.get_client('iam', region)
43
+
44
+ users = []
45
+ paginator = iam_client.get_paginator('list_users')
46
+
47
+ for page in paginator.paginate():
48
+ for user in page.get('Users', []):
49
+ user_name = user.get('UserName', '')
50
+
51
+ # Check if user has MFA
52
+ try:
53
+ mfa_devices = iam_client.list_mfa_devices(UserName=user_name)
54
+ has_mfa = len(mfa_devices.get('MFADevices', [])) > 0
55
+ except ClientError:
56
+ has_mfa = False
57
+
58
+ # Check if user has admin policies
59
+ is_admin = self._is_admin_user(iam_client, user_name)
60
+
61
+ if is_admin: # Only include admin users
62
+ users.append({
63
+ 'UserName': user_name,
64
+ 'UserArn': user.get('Arn', ''),
65
+ 'HasMFA': has_mfa,
66
+ 'IsAdmin': is_admin
67
+ })
68
+
69
+ logger.debug(f"Found {len(users)} admin IAM users")
70
+ return users
71
+
72
+ except ClientError as e:
73
+ logger.error(f"Error retrieving IAM users: {e}")
74
+ return []
75
+
76
+ def _is_admin_user(self, iam_client, user_name: str) -> bool:
77
+ """Check if user has administrative privileges."""
78
+ try:
79
+ # Check attached policies
80
+ attached_policies = iam_client.list_attached_user_policies(UserName=user_name)
81
+ for policy in attached_policies.get('AttachedPolicies', []):
82
+ policy_arn = policy.get('PolicyArn', '')
83
+ if 'AdministratorAccess' in policy_arn or 'PowerUserAccess' in policy_arn:
84
+ return True
85
+
86
+ # Check inline policies
87
+ inline_policies = iam_client.list_user_policies(UserName=user_name)
88
+ for policy_name in inline_policies.get('PolicyNames', []):
89
+ policy_doc = iam_client.get_user_policy(UserName=user_name, PolicyName=policy_name)
90
+ policy_document = policy_doc.get('PolicyDocument', {})
91
+ if self._has_admin_permissions(policy_document):
92
+ return True
93
+
94
+ # Check group memberships
95
+ groups = iam_client.list_groups_for_user(UserName=user_name)
96
+ for group in groups.get('Groups', []):
97
+ group_name = group.get('GroupName', '')
98
+ if 'admin' in group_name.lower():
99
+ return True
100
+
101
+ return False
102
+ except ClientError:
103
+ return False
104
+
105
+ def _has_admin_permissions(self, policy_document: Dict) -> bool:
106
+ """Check if policy document grants admin permissions."""
107
+ statements = policy_document.get('Statement', [])
108
+ for statement in statements:
109
+ if statement.get('Effect') == 'Allow':
110
+ actions = statement.get('Action', [])
111
+ if isinstance(actions, str):
112
+ actions = [actions]
113
+ if '*' in actions or 'iam:*' in actions:
114
+ return True
115
+ return False
116
+
117
+ def _evaluate_resource_compliance(
118
+ self,
119
+ resource: Dict[str, Any],
120
+ aws_factory: AWSClientFactory,
121
+ region: str
122
+ ) -> ComplianceResult:
123
+ """Evaluate if admin user has MFA enabled."""
124
+ user_name = resource.get('UserName', 'unknown')
125
+ has_mfa = resource.get('HasMFA', False)
126
+
127
+ if has_mfa:
128
+ evaluation_reason = f"IAM admin user '{user_name}' has MFA enabled."
129
+ compliance_status = ComplianceStatus.COMPLIANT
130
+ else:
131
+ evaluation_reason = (
132
+ f"IAM admin user '{user_name}' does not have MFA enabled. "
133
+ f"MFA is required for all administrative users."
134
+ )
135
+ compliance_status = ComplianceStatus.NON_COMPLIANT
136
+
137
+ return ComplianceResult(
138
+ resource_id=user_name,
139
+ resource_type="AWS::IAM::User",
140
+ compliance_status=compliance_status,
141
+ evaluation_reason=evaluation_reason,
142
+ config_rule_name=self.rule_name,
143
+ region=region
144
+ )
145
+
146
+ def _get_rule_remediation_steps(self) -> List[str]:
147
+ """Get remediation steps for enabling MFA for admin users."""
148
+ return [
149
+ "1. Enable MFA for IAM user via Console:",
150
+ " - Sign in to AWS Console",
151
+ " - Navigate to IAM > Users",
152
+ " - Select the user",
153
+ " - Click 'Security credentials' tab",
154
+ " - Under 'Multi-factor authentication (MFA)', click 'Assign MFA device'",
155
+ " - Choose MFA device type:",
156
+ " * Authenticator app (recommended)",
157
+ " * Security key (FIDO)",
158
+ " * Hardware TOTP token",
159
+ " - Follow the setup wizard",
160
+ "",
161
+ "2. Enable MFA via AWS CLI:",
162
+ " # For virtual MFA device",
163
+ " aws iam create-virtual-mfa-device \\",
164
+ " --virtual-mfa-device-name <user-name>-mfa \\",
165
+ " --outfile QRCode.png \\",
166
+ " --bootstrap-method QRCodePNG",
167
+ "",
168
+ " # Scan QR code with authenticator app, then enable",
169
+ " aws iam enable-mfa-device \\",
170
+ " --user-name <user-name> \\",
171
+ " --serial-number arn:aws:iam::<account-id>:mfa/<user-name>-mfa \\",
172
+ " --authentication-code-1 <code1> \\",
173
+ " --authentication-code-2 <code2>",
174
+ "",
175
+ "3. Enforce MFA with IAM policy:",
176
+ " {",
177
+ ' "Version": "2012-10-17",',
178
+ ' "Statement": [{',
179
+ ' "Sid": "DenyAllExceptListedIfNoMFA",',
180
+ ' "Effect": "Deny",',
181
+ ' "NotAction": [',
182
+ ' "iam:CreateVirtualMFADevice",',
183
+ ' "iam:EnableMFADevice",',
184
+ ' "iam:GetUser",',
185
+ ' "iam:ListMFADevices",',
186
+ ' "iam:ListVirtualMFADevices",',
187
+ ' "iam:ResyncMFADevice",',
188
+ ' "sts:GetSessionToken"',
189
+ " ],",
190
+ ' "Resource": "*",',
191
+ ' "Condition": {',
192
+ ' "BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}',
193
+ " }",
194
+ " }]",
195
+ " }",
196
+ "",
197
+ "4. Best practices:",
198
+ " - Require MFA for all admin users",
199
+ " - Use authenticator apps (Google Authenticator, Authy, etc.)",
200
+ " - Consider hardware security keys for highest security",
201
+ " - Store backup codes securely",
202
+ " - Regularly audit MFA compliance",
203
+ " - Disable console access for users without MFA",
204
+ "",
205
+ "Priority: CRITICAL - Admin access without MFA is a major security risk",
206
+ "Effort: Low - Can be enabled in minutes per user",
207
+ "",
208
+ "AWS Documentation:",
209
+ "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html"
210
+ ]
211
+
212
+
213
+ class CognitoMFAEnabledAssessment(BaseConfigRuleAssessment):
214
+ """
215
+ CIS Control 2.7 - Establish an Access Granting Process
216
+ AWS Config Rule: cognito-mfa-enabled
217
+
218
+ Ensures Cognito user pools have MFA enabled for user authentication.
219
+ """
220
+
221
+ def __init__(self):
222
+ super().__init__(
223
+ rule_name="cognito-mfa-enabled",
224
+ control_id="2.7",
225
+ resource_types=["AWS::Cognito::UserPool"]
226
+ )
227
+
228
+ def _get_resources(self, aws_factory: AWSClientFactory, resource_type: str, region: str) -> List[Dict[str, Any]]:
229
+ """Get all Cognito user pools and their MFA configuration."""
230
+ if resource_type != "AWS::Cognito::UserPool":
231
+ return []
232
+
233
+ try:
234
+ cognito_client = aws_factory.get_client('cognito-idp', region)
235
+
236
+ user_pools = []
237
+ paginator = cognito_client.get_paginator('list_user_pools')
238
+
239
+ for page in paginator.paginate(MaxResults=60):
240
+ for pool in page.get('UserPools', []):
241
+ pool_id = pool.get('Id', '')
242
+ pool_name = pool.get('Name', '')
243
+
244
+ try:
245
+ # Get detailed pool configuration
246
+ pool_details = cognito_client.describe_user_pool(UserPoolId=pool_id)
247
+ user_pool = pool_details.get('UserPool', {})
248
+
249
+ mfa_config = user_pool.get('MfaConfiguration', 'OFF')
250
+
251
+ user_pools.append({
252
+ 'UserPoolId': pool_id,
253
+ 'UserPoolName': pool_name,
254
+ 'MfaConfiguration': mfa_config,
255
+ 'MfaEnabled': mfa_config in ['ON', 'OPTIONAL']
256
+ })
257
+ except ClientError as e:
258
+ logger.warning(f"Error describing user pool {pool_id}: {e}")
259
+ continue
260
+
261
+ logger.debug(f"Found {len(user_pools)} Cognito user pools in {region}")
262
+ return user_pools
263
+
264
+ except ClientError as e:
265
+ logger.error(f"Error retrieving Cognito user pools from {region}: {e}")
266
+ return []
267
+
268
+ def _evaluate_resource_compliance(
269
+ self,
270
+ resource: Dict[str, Any],
271
+ aws_factory: AWSClientFactory,
272
+ region: str
273
+ ) -> ComplianceResult:
274
+ """Evaluate if Cognito user pool has MFA enabled."""
275
+ pool_id = resource.get('UserPoolId', 'unknown')
276
+ pool_name = resource.get('UserPoolName', '')
277
+ mfa_config = resource.get('MfaConfiguration', 'OFF')
278
+ mfa_enabled = resource.get('MfaEnabled', False)
279
+
280
+ if mfa_enabled:
281
+ evaluation_reason = (
282
+ f"Cognito user pool '{pool_name}' has MFA configured as '{mfa_config}'."
283
+ )
284
+ compliance_status = ComplianceStatus.COMPLIANT
285
+ else:
286
+ evaluation_reason = (
287
+ f"Cognito user pool '{pool_name}' does not have MFA enabled. "
288
+ f"Current configuration: {mfa_config}"
289
+ )
290
+ compliance_status = ComplianceStatus.NON_COMPLIANT
291
+
292
+ return ComplianceResult(
293
+ resource_id=pool_id,
294
+ resource_type="AWS::Cognito::UserPool",
295
+ compliance_status=compliance_status,
296
+ evaluation_reason=evaluation_reason,
297
+ config_rule_name=self.rule_name,
298
+ region=region
299
+ )
300
+
301
+ def _get_rule_remediation_steps(self) -> List[str]:
302
+ """Get remediation steps for enabling Cognito MFA."""
303
+ return [
304
+ "1. Enable MFA for Cognito user pool via Console:",
305
+ " - Navigate to Amazon Cognito",
306
+ " - Select 'User pools'",
307
+ " - Select the user pool",
308
+ " - Click 'Sign-in experience' tab",
309
+ " - Under 'Multi-factor authentication', click 'Edit'",
310
+ " - Select MFA enforcement:",
311
+ " * Required - MFA required for all users",
312
+ " * Optional - Users can choose to enable MFA",
313
+ " - Select MFA methods:",
314
+ " * SMS text message",
315
+ " * Authenticator apps (TOTP)",
316
+ " - Click 'Save changes'",
317
+ "",
318
+ "2. Enable MFA via AWS CLI:",
319
+ " aws cognito-idp set-user-pool-mfa-config \\",
320
+ " --user-pool-id <pool-id> \\",
321
+ " --mfa-configuration ON \\",
322
+ " --software-token-mfa-configuration Enabled=true \\",
323
+ " --region <region>",
324
+ "",
325
+ "3. Enable SMS MFA:",
326
+ " aws cognito-idp set-user-pool-mfa-config \\",
327
+ " --user-pool-id <pool-id> \\",
328
+ " --mfa-configuration ON \\",
329
+ " --sms-mfa-configuration SmsConfiguration={SnsCallerArn=<sns-role-arn>} \\",
330
+ " --region <region>",
331
+ "",
332
+ "4. Best practices:",
333
+ " - Use 'Required' for production applications",
334
+ " - Prefer authenticator apps over SMS",
335
+ " - Configure both SMS and TOTP for flexibility",
336
+ " - Set up SNS for SMS delivery",
337
+ " - Monitor MFA usage with CloudWatch",
338
+ "",
339
+ "Priority: HIGH - MFA protects user accounts from compromise",
340
+ "Effort: Low - Can be enabled quickly",
341
+ "",
342
+ "AWS Documentation:",
343
+ "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html"
344
+ ]
345
+
346
+
347
+ class VPNMFAEnabledAssessment(BaseConfigRuleAssessment):
348
+ """
349
+ CIS Control 2.15 - Secure Remote Access
350
+ AWS Config Rule: vpn-mfa-enabled
351
+
352
+ Ensures Client VPN endpoints require MFA for authentication.
353
+ """
354
+
355
+ def __init__(self):
356
+ super().__init__(
357
+ rule_name="vpn-mfa-enabled",
358
+ control_id="2.15",
359
+ resource_types=["AWS::EC2::ClientVpnEndpoint"]
360
+ )
361
+
362
+ def _get_resources(self, aws_factory: AWSClientFactory, resource_type: str, region: str) -> List[Dict[str, Any]]:
363
+ """Get all Client VPN endpoints and their MFA configuration."""
364
+ if resource_type != "AWS::EC2::ClientVpnEndpoint":
365
+ return []
366
+
367
+ try:
368
+ ec2_client = aws_factory.get_client('ec2', region)
369
+
370
+ vpn_endpoints = []
371
+ paginator = ec2_client.get_paginator('describe_client_vpn_endpoints')
372
+
373
+ for page in paginator.paginate():
374
+ for endpoint in page.get('ClientVpnEndpoints', []):
375
+ endpoint_id = endpoint.get('ClientVpnEndpointId', '')
376
+
377
+ # Check authentication options
378
+ auth_options = endpoint.get('AuthenticationOptions', [])
379
+ has_mfa = False
380
+ auth_types = []
381
+
382
+ for auth in auth_options:
383
+ auth_type = auth.get('Type', '')
384
+ auth_types.append(auth_type)
385
+
386
+ # Check if MFA is enabled for this auth method
387
+ if auth_type == 'federated-authentication':
388
+ # SAML-based auth can enforce MFA at IdP level
389
+ has_mfa = True
390
+ elif auth_type == 'directory-service-authentication':
391
+ # AD can enforce MFA
392
+ has_mfa = True
393
+
394
+ vpn_endpoints.append({
395
+ 'ClientVpnEndpointId': endpoint_id,
396
+ 'Description': endpoint.get('Description', ''),
397
+ 'Status': endpoint.get('Status', {}).get('Code', ''),
398
+ 'AuthenticationOptions': auth_types,
399
+ 'HasMFA': has_mfa
400
+ })
401
+
402
+ logger.debug(f"Found {len(vpn_endpoints)} Client VPN endpoints in {region}")
403
+ return vpn_endpoints
404
+
405
+ except ClientError as e:
406
+ logger.error(f"Error retrieving Client VPN endpoints from {region}: {e}")
407
+ return []
408
+
409
+ def _evaluate_resource_compliance(
410
+ self,
411
+ resource: Dict[str, Any],
412
+ aws_factory: AWSClientFactory,
413
+ region: str
414
+ ) -> ComplianceResult:
415
+ """Evaluate if VPN endpoint has MFA enabled."""
416
+ endpoint_id = resource.get('ClientVpnEndpointId', 'unknown')
417
+ has_mfa = resource.get('HasMFA', False)
418
+ auth_options = resource.get('AuthenticationOptions', [])
419
+
420
+ if has_mfa:
421
+ evaluation_reason = (
422
+ f"Client VPN endpoint '{endpoint_id}' uses authentication methods that support MFA: "
423
+ f"{', '.join(auth_options)}"
424
+ )
425
+ compliance_status = ComplianceStatus.COMPLIANT
426
+ else:
427
+ evaluation_reason = (
428
+ f"Client VPN endpoint '{endpoint_id}' does not have MFA-capable authentication configured. "
429
+ f"Current auth: {', '.join(auth_options) if auth_options else 'None'}"
430
+ )
431
+ compliance_status = ComplianceStatus.NON_COMPLIANT
432
+
433
+ return ComplianceResult(
434
+ resource_id=endpoint_id,
435
+ resource_type="AWS::EC2::ClientVpnEndpoint",
436
+ compliance_status=compliance_status,
437
+ evaluation_reason=evaluation_reason,
438
+ config_rule_name=self.rule_name,
439
+ region=region
440
+ )
441
+
442
+ def _get_rule_remediation_steps(self) -> List[str]:
443
+ """Get remediation steps for enabling VPN MFA."""
444
+ return [
445
+ "1. Configure MFA for Client VPN using SAML-based authentication:",
446
+ " - Set up SAML 2.0 identity provider (Okta, Azure AD, etc.)",
447
+ " - Configure MFA in your IdP",
448
+ " - Create Client VPN endpoint with federated authentication:",
449
+ " ",
450
+ " aws ec2 create-client-vpn-endpoint \\",
451
+ " --client-cidr-block 10.0.0.0/16 \\",
452
+ " --server-certificate-arn <cert-arn> \\",
453
+ " --authentication-options Type=federated-authentication,SAMLProviderArn=<saml-provider-arn> \\",
454
+ " --connection-log-options Enabled=true,CloudwatchLogGroup=<log-group> \\",
455
+ " --region <region>",
456
+ "",
457
+ "2. Configure MFA using AWS Directory Service:",
458
+ " - Set up AWS Managed Microsoft AD or AD Connector",
459
+ " - Enable MFA in Active Directory",
460
+ " - Create Client VPN with directory authentication:",
461
+ " ",
462
+ " aws ec2 create-client-vpn-endpoint \\",
463
+ " --client-cidr-block 10.0.0.0/16 \\",
464
+ " --server-certificate-arn <cert-arn> \\",
465
+ " --authentication-options Type=directory-service-authentication,ActiveDirectory={DirectoryId=<directory-id>} \\",
466
+ " --region <region>",
467
+ "",
468
+ "3. Modify existing VPN endpoint (requires recreation):",
469
+ " Note: You cannot modify authentication options on existing endpoints",
470
+ " You must create a new endpoint with MFA-enabled authentication",
471
+ "",
472
+ "4. Best practices:",
473
+ " - Use SAML-based authentication with enterprise IdP",
474
+ " - Enforce MFA at the IdP level",
475
+ " - Enable connection logging",
476
+ " - Use certificate-based authentication in addition to MFA",
477
+ " - Implement least privilege access",
478
+ " - Monitor VPN connections with CloudWatch",
479
+ "",
480
+ "Priority: CRITICAL - VPN access without MFA is a major security risk",
481
+ "Effort: High - Requires IdP setup and VPN endpoint recreation",
482
+ "",
483
+ "AWS Documentation:",
484
+ "https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/client-authentication.html"
485
+ ]