Skip to content

Commit d8ad886

Browse files
authored
refactor!(beyondinsight_password_safe): rewrite managedsystem (elastic#15007)
refactor(beyondinsight_password_safe): rewrite managedsystem Rewrite of the managedsystem data stream to improve code maintainability and reliability, applying the same improvements made to managedaccount. The new implementation requires Elastic Agent 8.18.0 or greater due to sprintf usage for credential formatting. Key improvements: - Enhanced CEL program with proper session management and retry logic - Automatic re-authentication when sessions expire (401 responses) - Consistent event.original field containing JSON event data - Drop event processor to filter out dummy CEL control events - Enhanced ingest pipeline with terminate processors (requires ES 8.16.0) - Moved event.dataset and event.module to constant_keyword mappings - Added system test with session expiration scenarios - Added pipeline test for nullable fields handling - Updated to use RFC 5737 documentation IP addresses (198.51.100.0/24) - Fixed field name inconsistencies compared to docs (DnsName -> DNSName) Test improvements: - Added Docker mock server configuration for E2E testing - Added policy tests (note: does not demonstrate secret rendering) - Enhanced pipeline tests with null value handling Relates elastic#14999
1 parent 6f0e62d commit d8ad886

File tree

18 files changed

+873
-243
lines changed

18 files changed

+873
-243
lines changed

packages/beyondinsight_password_safe/changelog.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
- version: "0.7.0"
2+
changes:
3+
- description: For the `managedsystem` data stream, fixed session management to automatically re-authenticate when sessions expire.
4+
type: bugfix
5+
link: https://github.com/elastic/integrations/pull/15007
6+
- description: For the `managedsystem` data stream, renamed fields to match proper snake_case naming - `ipaddress` to `ip_address` and `isarelease_duration` to `isa_release_duration`.
7+
type: breaking-change
8+
link: https://github.com/elastic/integrations/pull/15007
19
- version: "0.6.0"
210
changes:
311
- description: For the `managedaccount` data stream, fixed session management to automatically re-authenticate when sessions expire.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
services:
2+
beyondinsight-managedsystem-cel:
3+
image: docker.elastic.co/observability/stream:v0.20.0
4+
ports:
5+
- 8080
6+
volumes:
7+
- ./files:/files:ro
8+
environment:
9+
PORT: '8080'
10+
command:
11+
- http-server
12+
- --addr=:8080
13+
- --config=/files/config.yml
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# BeyondInsight Password Safe - Managed Systems Test Mock Configuration
2+
#
3+
# Test Scenario: Simulates paginated retrieval of managed systems with session expiration and re-authentication:
4+
# 1. Initial authentication via SignAppin endpoint (returns 200, sets session cookie)
5+
# 2. First ManagedSystems request with limit=1&offset=0 (returns 200, first session)
6+
# 3. Second ManagedSystems request with limit=1&offset=1 (returns 401, session expired)
7+
# 4. Re-authentication via SignAppin endpoint (returns 200, new session cookie)
8+
# 5. Retry ManagedSystems request with limit=1&offset=1 (returns 200, second session)
9+
# 6. Final ManagedSystems request with limit=1&offset=2 (returns 200, empty data array - no more data)
10+
#
11+
# This tests the integration's ability to handle:
12+
# - Session-based authentication with BeyondTrust API
13+
# - Paginated data retrieval with limit/offset parameters
14+
# - Session expiration (401) and automatic re-authentication
15+
# - Proper handling of empty result sets indicating end of pagination
16+
17+
rules:
18+
# Auth
19+
- path: "/BeyondTrust/api/public/v3/Auth/SignAppin"
20+
methods: ["POST"]
21+
request_headers:
22+
Authorization: ['PS-Auth key=test_api_key; runas=testuser; pwd=\[password\];']
23+
Content-Type: ['application/json']
24+
responses:
25+
- status_code: 200
26+
headers:
27+
Content-Type: ['application/json']
28+
Set-Cookie: ['ASP.NET_SessionId={{ if eq .req_num 1 }}cookie_value1{{ else }}cookie_value2{{ end }}']
29+
body: |
30+
{{ minify_json `
31+
{
32+
"UserId": 1,
33+
"SID": null,
34+
"EmailAddress": "[email protected]",
35+
"UserName": "testuser",
36+
"Name": "Test User"
37+
}
38+
`}}
39+
40+
- path: "/BeyondTrust/api/public/v3/ManagedSystems"
41+
methods: ["GET"]
42+
query_params:
43+
offset: '0'
44+
request_headers:
45+
Content-Type: ['application/json']
46+
Cookie: ['ASP.NET_SessionId=cookie_value1']
47+
responses:
48+
- status_code: 200
49+
headers:
50+
Content-Type: ['application/json']
51+
body: |-
52+
{{ minify_json `
53+
{
54+
"Data": [
55+
{
56+
"ManagedSystemID": 13,
57+
"EntityTypeID": 1,
58+
"AssetID": 13,
59+
"DatabaseID": 5,
60+
"DirectoryID": 3,
61+
"CloudID": 1,
62+
"WorkgroupID": 1,
63+
"HostName": "AardvarkAgreement",
64+
"DNSName": "AardvarkAgreement.example.com",
65+
"IPAddress": "198.51.100.10",
66+
"InstanceName": "InstanceOne",
67+
"IsDefaultInstance": true,
68+
"Template": "ServerTemplate",
69+
"ForestName": "PrimaryForest",
70+
"UseSSL": true,
71+
"OracleInternetDirectoryID": "550e8400-e29b-41d4-a716-446655440000",
72+
"OracleInternetDirectoryServiceName": "OiDService",
73+
"SystemName": "AardvarkAgreement",
74+
"PlatformID": 4,
75+
"NetBiosName": "AardvarkNet",
76+
"Port": 8080,
77+
"Timeout": 30,
78+
"Description": "Primary Managed System for AardvarkAgreement",
79+
"ContactEmail": "[email protected]",
80+
"PasswordRuleID": 0,
81+
"DSSKeyRuleID": 0,
82+
"ReleaseDuration": 120,
83+
"MaxReleaseDuration": 525600,
84+
"ISAReleaseDuration": 120,
85+
"AutoManagementFlag": true,
86+
"FunctionalAccountID": 14,
87+
"LoginAccountID": 20,
88+
"ElevationCommand": "sudo",
89+
"SshKeyEnforcementMode": 1,
90+
"CheckPasswordFlag": false,
91+
"ChangePasswordAfterAnyReleaseFlag": false,
92+
"ResetPasswordOnMismatchFlag": false,
93+
"ChangeFrequencyType": "first",
94+
"ChangeFrequencyDays": 30,
95+
"ChangeTime": "23:30",
96+
"AccountNameFormat": 0,
97+
"RemoteClientType": "None",
98+
"ApplicationHostID": 2,
99+
"IsApplicationHost": false,
100+
"AccessURL": "http://aardvarkagreement.com/manage"
101+
}
102+
],
103+
"TotalCount": 2
104+
}
105+
`}}
106+
107+
- path: "/BeyondTrust/api/public/v3/ManagedSystems"
108+
methods: ["GET"]
109+
query_params:
110+
offset: '1'
111+
request_headers:
112+
Content-Type: ['application/json']
113+
Cookie: ['ASP.NET_SessionId=cookie_value1']
114+
responses:
115+
- status_code: 401
116+
headers:
117+
Content-Type: ['application/json']
118+
body: >-
119+
"User not authenticated"
120+
121+
- path: "/BeyondTrust/api/public/v3/ManagedSystems"
122+
methods: ["GET"]
123+
query_params:
124+
offset: '1'
125+
limit: '1'
126+
request_headers:
127+
Content-Type: ['application/json']
128+
Cookie: ['ASP.NET_SessionId=cookie_value2']
129+
responses:
130+
- status_code: 200
131+
headers:
132+
Content-Type: ['application/json']
133+
body: |-
134+
{{ minify_json `
135+
{
136+
"Data": [
137+
{
138+
"ManagedSystemID": 14,
139+
"EntityTypeID": 1,
140+
"AssetID": 14,
141+
"DatabaseID": 6,
142+
"DirectoryID": 4,
143+
"CloudID": 2,
144+
"WorkgroupID": 2,
145+
"HostName": "SecondSystem",
146+
"DNSName": "secondsystem.example.com",
147+
"IPAddress": "198.51.100.20",
148+
"InstanceName": "Primary",
149+
"IsDefaultInstance": true,
150+
"Template": "ServerTemplate",
151+
"ForestName": "SecondaryForest",
152+
"UseSSL": true,
153+
"OracleInternetDirectoryID": "550e8400-e29b-41d4-a716-446655440001",
154+
"OracleInternetDirectoryServiceName": "OiDService2",
155+
"SystemName": "SecondSystem",
156+
"PlatformID": 5,
157+
"NetBiosName": "SecondNet",
158+
"Port": 8081,
159+
"Timeout": 60,
160+
"Description": "Secondary Managed System",
161+
"ContactEmail": "[email protected]",
162+
"PasswordRuleID": 1,
163+
"DSSKeyRuleID": 1,
164+
"ReleaseDuration": 240,
165+
"MaxReleaseDuration": 525600,
166+
"ISAReleaseDuration": 240,
167+
"AutoManagementFlag": false,
168+
"FunctionalAccountID": 15,
169+
"LoginAccountID": 21,
170+
"ElevationCommand": "su",
171+
"SshKeyEnforcementMode": 2,
172+
"CheckPasswordFlag": true,
173+
"ChangePasswordAfterAnyReleaseFlag": true,
174+
"ResetPasswordOnMismatchFlag": true,
175+
"ChangeFrequencyType": "daily",
176+
"ChangeFrequencyDays": 1,
177+
"ChangeTime": "02:00",
178+
"AccountNameFormat": 1,
179+
"RemoteClientType": "SSH",
180+
"ApplicationHostID": 3,
181+
"IsApplicationHost": true,
182+
"AccessURL": "https://secondsystem.example.com/manage"
183+
}
184+
],
185+
"TotalCount": 2
186+
}
187+
`}}
188+
189+
- path: "/BeyondTrust/api/public/v3/ManagedSystems"
190+
methods: ["GET"]
191+
request_headers:
192+
Content-Type: ['application/json']
193+
Cookie: ['ASP.NET_SessionId=cookie_value2']
194+
responses:
195+
- status_code: 200
196+
headers:
197+
Content-Type: ['application/json']
198+
body: |-
199+
{{ minify_json `
200+
{
201+
"Data": [],
202+
"TotalCount": 2
203+
}
204+
`}}

packages/beyondinsight_password_safe/data_stream/managedsystem/_dev/test/pipeline/test-common-config.yml

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"events": [
3+
{
4+
"labels": {
5+
"test_description": "This tests the pipeline using an event that includes every nullable field documented by the API."
6+
},
7+
"event": {
8+
"original" : "{\"ManagedSystemID\":15,\"EntityTypeID\":2,\"AssetID\":null,\"DatabaseID\":null,\"DirectoryID\":null,\"CloudID\":null,\"WorkgroupID\":3,\"HostName\":\"MinimalSystem\",\"DNSName\":\"minimal.example.com\",\"IPAddress\":\"198.51.100.30\",\"InstanceName\":\"Default\",\"IsDefaultInstance\":null,\"Template\":\"BasicTemplate\",\"ForestName\":\"TestForest\",\"UseSSL\":null,\"OracleInternetDirectoryID\":null,\"OracleInternetDirectoryServiceName\":\"DefaultOiD\",\"SystemName\":\"MinimalSystem\",\"PlatformID\":6,\"NetBiosName\":\"MinimalNet\",\"Port\":null,\"Timeout\":15,\"Description\":\"Minimal system with null values\",\"ContactEmail\":\"[email protected]\",\"PasswordRuleID\":1,\"DSSKeyRuleID\":null,\"ReleaseDuration\":60,\"MaxReleaseDuration\":300000,\"ISAReleaseDuration\":90,\"AutoManagementFlag\":false,\"FunctionalAccountID\":null,\"LoginAccountID\":null,\"ElevationCommand\":null,\"SshKeyEnforcementMode\":null,\"CheckPasswordFlag\":true,\"ChangePasswordAfterAnyReleaseFlag\":true,\"ResetPasswordOnMismatchFlag\":false,\"ChangeFrequencyType\":\"weekly\",\"ChangeFrequencyDays\":7,\"ChangeTime\":\"03:00\",\"AccountNameFormat\":1,\"RemoteClientType\":\"RDP\",\"ApplicationHostID\":null,\"IsApplicationHost\":false,\"AccessURL\":\"https://minimal.example.com/access\"}"
9+
}
10+
}
11+
]
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{
2+
"expected": [
3+
{
4+
"beyondinsight_password_safe": {
5+
"managedsystem": {
6+
"access_url": "https://minimal.example.com/access",
7+
"account_name_format": 1,
8+
"auto_management_flag": false,
9+
"change_frequency_days": 7,
10+
"change_frequency_type": "weekly",
11+
"change_password_after_any_release_flag": true,
12+
"change_time": "03:00",
13+
"check_password_flag": true,
14+
"contact_email": "[email protected]",
15+
"description": "Minimal system with null values",
16+
"dns_name": "minimal.example.com",
17+
"entity_type_id": 2,
18+
"forest_name": "TestForest",
19+
"host_name": "MinimalSystem",
20+
"instance_name": "Default",
21+
"ip_address": "198.51.100.30",
22+
"is_application_host": false,
23+
"isa_release_duration": 90,
24+
"managed_system_id": 15,
25+
"max_release_duration": 300000,
26+
"net_bios_name": "MinimalNet",
27+
"oracle_internet_directory_service_name": "DefaultOiD",
28+
"password_rule_id": 1,
29+
"platform_id": 6,
30+
"release_duration": 60,
31+
"remote_client_type": "RDP",
32+
"reset_password_on_mismatch_flag": false,
33+
"system_name": "MinimalSystem",
34+
"template": "BasicTemplate",
35+
"timeout": 15,
36+
"workgroup_id": 3
37+
}
38+
},
39+
"ecs": {
40+
"version": "8.11.0"
41+
},
42+
"event": {
43+
"category": [
44+
"iam"
45+
],
46+
"kind": "asset",
47+
"original": "{\"ManagedSystemID\":15,\"EntityTypeID\":2,\"AssetID\":null,\"DatabaseID\":null,\"DirectoryID\":null,\"CloudID\":null,\"WorkgroupID\":3,\"HostName\":\"MinimalSystem\",\"DNSName\":\"minimal.example.com\",\"IPAddress\":\"198.51.100.30\",\"InstanceName\":\"Default\",\"IsDefaultInstance\":null,\"Template\":\"BasicTemplate\",\"ForestName\":\"TestForest\",\"UseSSL\":null,\"OracleInternetDirectoryID\":null,\"OracleInternetDirectoryServiceName\":\"DefaultOiD\",\"SystemName\":\"MinimalSystem\",\"PlatformID\":6,\"NetBiosName\":\"MinimalNet\",\"Port\":null,\"Timeout\":15,\"Description\":\"Minimal system with null values\",\"ContactEmail\":\"[email protected]\",\"PasswordRuleID\":1,\"DSSKeyRuleID\":null,\"ReleaseDuration\":60,\"MaxReleaseDuration\":300000,\"ISAReleaseDuration\":90,\"AutoManagementFlag\":false,\"FunctionalAccountID\":null,\"LoginAccountID\":null,\"ElevationCommand\":null,\"SshKeyEnforcementMode\":null,\"CheckPasswordFlag\":true,\"ChangePasswordAfterAnyReleaseFlag\":true,\"ResetPasswordOnMismatchFlag\":false,\"ChangeFrequencyType\":\"weekly\",\"ChangeFrequencyDays\":7,\"ChangeTime\":\"03:00\",\"AccountNameFormat\":1,\"RemoteClientType\":\"RDP\",\"ApplicationHostID\":null,\"IsApplicationHost\":false,\"AccessURL\":\"https://minimal.example.com/access\"}",
48+
"type": [
49+
"info"
50+
]
51+
},
52+
"host": {
53+
"domain": "minimal.example.com",
54+
"geo": {
55+
"city_name": "Amsterdam",
56+
"continent_name": "Europe",
57+
"country_iso_code": "NL",
58+
"country_name": "Netherlands",
59+
"location": {
60+
"lat": 52.37404,
61+
"lon": 4.88969
62+
},
63+
"region_iso_code": "NL-NH",
64+
"region_name": "North Holland"
65+
},
66+
"ip": [
67+
"198.51.100.30"
68+
],
69+
"name": "MinimalSystem"
70+
},
71+
"labels": {
72+
"test_description": "This tests the pipeline using an event that includes every nullable field documented by the API."
73+
},
74+
"related": {
75+
"hosts": [
76+
"MinimalSystem",
77+
"minimal.example.com",
78+
"198.51.100.30"
79+
],
80+
"user": [
81+
82+
]
83+
},
84+
"url": {
85+
"full": "https://minimal.example.com/access"
86+
},
87+
"user": {
88+
"email": "[email protected]"
89+
}
90+
}
91+
]
92+
}

packages/beyondinsight_password_safe/data_stream/managedsystem/_dev/test/pipeline/test-managedsystem.json

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,8 @@
11
{
22
"events": [
33
{
4-
"message": {
5-
"ManagedSystemID": 13,
6-
"EntityTypeID": 1,
7-
"AssetID": 13,
8-
"DatabaseID": 5,
9-
"DirectoryID": 3,
10-
"CloudID": 1,
11-
"WorkgroupID": 1,
12-
"HostName": "AardvarkAgreement",
13-
"DnsName": "AardvarkAgreement.example.com",
14-
"IPAddress": "175.16.199.0",
15-
"InstanceName": "InstanceOne",
16-
"IsDefaultInstance": true,
17-
"Template": "ServerTemplate",
18-
"ForestName": "PrimaryForest",
19-
"UseSSL": true,
20-
"OracleInternetDirectoryID": "550e8400-e29b-41d4-a716-446655440000",
21-
"OracleInternetDirectoryServiceName": "OiDService",
22-
"SystemName": "AardvarkAgreement",
23-
"PlatformID": 4,
24-
"NetBiosName": "AardvarkNet",
25-
"Port": 8080,
26-
"Timeout": 30,
27-
"Description": "Primary Managed System for AardvarkAgreement",
28-
"ContactEmail": "[email protected]",
29-
"PasswordRuleID": 0,
30-
"DSSKeyRuleID": 0,
31-
"ReleaseDuration": 120,
32-
"MaxReleaseDuration": 525600,
33-
"ISAReleaseDuration": 120,
34-
"AutoManagementFlag": true,
35-
"FunctionalAccountID": 14,
36-
"LoginAccountID": 20,
37-
"ElevationCommand": "sudo",
38-
"SshKeyEnforcementMode": 1,
39-
"CheckPasswordFlag": false,
40-
"ChangePasswordAfterAnyReleaseFlag": false,
41-
"ResetPasswordOnMismatchFlag": false,
42-
"ChangeFrequencyType": "first",
43-
"ChangeFrequencyDays": 30,
44-
"ChangeTime": "23:30",
45-
"AccountNameFormat": 0,
46-
"RemoteClientType": "None",
47-
"ApplicationHostID": 2,
48-
"IsApplicationHost": false,
49-
"AccessURL": "http://aardvarkagreement.com/manage"
4+
"event": {
5+
"original" : "{\"ManagedSystemID\":13,\"EntityTypeID\":1,\"AssetID\":13,\"DatabaseID\":5,\"DirectoryID\":3,\"CloudID\":1,\"WorkgroupID\":1,\"HostName\":\"AardvarkAgreement\",\"DNSName\":\"AardvarkAgreement.example.com\",\"IPAddress\":\"198.51.100.10\",\"InstanceName\":\"InstanceOne\",\"IsDefaultInstance\":true,\"Template\":\"ServerTemplate\",\"ForestName\":\"PrimaryForest\",\"UseSSL\":true,\"OracleInternetDirectoryID\":\"550e8400-e29b-41d4-a716-446655440000\",\"OracleInternetDirectoryServiceName\":\"OiDService\",\"SystemName\":\"AardvarkAgreement\",\"PlatformID\":4,\"NetBiosName\":\"AardvarkNet\",\"Port\":8080,\"Timeout\":30,\"Description\":\"Primary Managed System for AardvarkAgreement\",\"ContactEmail\":\"[email protected]\",\"PasswordRuleID\":0,\"DSSKeyRuleID\":0,\"ReleaseDuration\":120,\"MaxReleaseDuration\":525600,\"ISAReleaseDuration\":120,\"AutoManagementFlag\":true,\"FunctionalAccountID\":14,\"LoginAccountID\":20,\"ElevationCommand\":\"sudo\",\"SshKeyEnforcementMode\":1,\"CheckPasswordFlag\":false,\"ChangePasswordAfterAnyReleaseFlag\":false,\"ResetPasswordOnMismatchFlag\":false,\"ChangeFrequencyType\":\"first\",\"ChangeFrequencyDays\":30,\"ChangeTime\":\"23:30\",\"AccountNameFormat\":0,\"RemoteClientType\":\"None\",\"ApplicationHostID\":2,\"IsApplicationHost\":false,\"AccessURL\":\"http://aardvarkagreement.com/manage\"}"
506
}
517
}
528
]

0 commit comments

Comments
 (0)