Skip to content

Commit 93c0ddd

Browse files
authored
Add RDP MFA Caching Password and SSH CA Support (#42)
* Add RDP MFA Caching Password and SSH CA Support * Add RDP MFA Caching Password and SSH CA Support
1 parent 9ac6f3f commit 93c0ddd

File tree

17 files changed

+553
-284
lines changed

17 files changed

+553
-284
lines changed

README.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ CyberArk's Official SDK and CLI for different services operations
3939
- [x] SIA K8S Service
4040
- [x] SIA DB Service
4141
- [x] SIA Access Service
42+
- [x] SIA SSH CA Service
4243
- [x] Session Monitoring Service
4344
- [x] Identity Users Service
4445
- [x] Identity Roles Service
@@ -225,8 +226,9 @@ The following services and commands are supported:
225226
- <b>certificates</b> - SIA Certificates Management
226227
- <b>db</b> - SIA DB Enduser Operations
227228
- <b>sso</b> - SIA SSO Enduser Operations
228-
- <b>k8s</b> - SIA kubernetes service
229-
- <b>access</b> - SIA access service
229+
- <b>k8s</b> - SIA Kubernetes Service
230+
- <b>access</b> - SIA Access Service
231+
- <b>ssh-ca</b> - SIA SSH CA Service
230232
- <b>sm</b> - Session Monitoring Service
231233
- <b>identity</b> - Identity Service
232234
- <b>users</b> - Identity Users Management
@@ -311,6 +313,11 @@ Generate a short lived SSO password for databases connection
311313
ark exec sia sso short-lived-password
312314
```
313315
316+
Generate a short lived SSO password for RDP connection
317+
```shell
318+
ark exec sia sso short-lived-password --service DPA-RDP
319+
```
320+
314321
Generate a short lived SSO oracle wallet for oracle database connection
315322
```shell
316323
ark exec sia sso short-lived-oracle-wallet --folder ~/wallet
@@ -326,6 +333,31 @@ Generate kubectl config file and save on specific path
326333
ark exec sia k8s generate-kubeconfig --folder=/Users/My.User/.kube
327334
```
328335
336+
Generate new SSH CA Key version
337+
```shell
338+
ark exec sia ssh-ca generate-new-ca
339+
```
340+
341+
Deactivate previous SSH CA Key version
342+
```shell
343+
ark exec sia ssh-ca deactivate-previous-ca
344+
```
345+
346+
Reactivate previous SSH CA Key version
347+
```shell
348+
ark exec sia ssh-ca reactivate-previous-ca
349+
```
350+
351+
Get SSH CA public key
352+
```shell
353+
ark exec sia ssh-ca public-key
354+
```
355+
356+
Get SSH CA public key script
357+
```shell
358+
ark exec sia ssh-ca public-key-script
359+
```
360+
329361
Create a PCloud Safe
330362
```shell
331363
ark exec pcloud safes add-safe --safe-name=safe

ark_sdk_python/ark_api.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ def sia_access(self) -> "ArkSIAAccessService":
152152

153153
return cast(ArkSIAAccessService, self.service(ArkSIAAccessService))
154154

155+
@property
156+
def sia_ssh_ca(self) -> "ArkSIASSHCAService":
157+
"""
158+
Returns the SIA SSH CA service if the appropriate authenticators were given
159+
160+
Returns:
161+
ArkSIASSHCAService: _description_
162+
"""
163+
from ark_sdk_python.services.sia.ssh_ca import ArkSIASSHCAService
164+
165+
return cast(ArkSIASSHCAService, self.service(ArkSIASSHCAService))
166+
155167
@property
156168
def sia_workspaces_db(self) -> "ArkSIADBWorkspaceService":
157169
"""

ark_sdk_python/auth/identity/ark_identity_service_user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111

1212
from ark_sdk_python.auth.identity.ark_identity_fqdn_resolver import ArkIdentityFQDNResolver
1313
from ark_sdk_python.common import ArkKeyring, ArkSystemConfig, get_logger
14+
from ark_sdk_python.common.ark_jwt_utils import ArkJWTUtils
1415
from ark_sdk_python.common.env import DEPLOY_ENV, IDENTITY_ENV_URLS, AwsEnv
1516
from ark_sdk_python.models import ArkAuthException, ArkProfile
1617
from ark_sdk_python.models.auth import ArkAuthMethod, ArkToken, ArkTokenType
17-
from ark_sdk_python.common.ark_jwt_utils import ArkJWTUtils
1818

1919

2020
class ArkIdentityServiceUser:

ark_sdk_python/models/actions/services/ark_sia_exec_action_consts.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
ArkSIAVMGetSecret,
4949
ArkSIAVMSecretsFilter,
5050
)
51+
from ark_sdk_python.models.services.sia.ssh_ca.ark_sia_get_ssh_public_key import ArkSIAGetSSHPublicKey
5152
from ark_sdk_python.models.services.sia.sso import (
5253
ArkSIASSOGetShortLivedClientCertificate,
5354
ArkSIASSOGetShortLivedOracleWallet,
@@ -232,6 +233,17 @@
232233
action_name='access',
233234
schemas=ACCESS_ACTION_TO_SCHEMA_MAP,
234235
)
236+
SSH_CA_ACTION_TO_SCHEMA_MAP: Final[Dict[str, Optional[Type[ArkModel]]]] = {
237+
'generate-new-ca': None,
238+
'deactivate-previous-ca': None,
239+
'reactivate-previous-ca': None,
240+
'public-key': ArkSIAGetSSHPublicKey,
241+
'public-key-script': ArkSIAGetSSHPublicKey,
242+
}
243+
SSH_CA_ACTION: Final[ArkServiceActionDefinition] = ArkServiceActionDefinition(
244+
action_name='ssh-ca',
245+
schemas=SSH_CA_ACTION_TO_SCHEMA_MAP,
246+
)
235247
SIA_ACTIONS: Final[ArkServiceActionDefinition] = ArkServiceActionDefinition(
236248
action_name='sia',
237249
subactions=[
@@ -243,5 +255,6 @@
243255
CERTIFICATES_ACTION,
244256
K8S_ACTION,
245257
ACCESS_ACTION,
258+
SSH_CA_ACTION,
246259
],
247260
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from ark_sdk_python.models.services.sia.ssh_ca.ark_sia_get_ssh_public_key import ArkSIAGetSSHPublicKey
2+
3+
__all__ = [
4+
'ArkSIAGetSSHPublicKey',
5+
]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from typing import Optional
2+
3+
from pydantic import Field
4+
5+
from ark_sdk_python.models import ArkModel
6+
7+
8+
class ArkSIAGetSSHPublicKey(ArkModel):
9+
output_file: Optional[str] = Field(default=None, description='Save output to file')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
from typing import Literal
2+
13
from pydantic import Field
24

35
from ark_sdk_python.models import ArkModel
46

57

68
class ArkSIASSOGetShortLivedPassword(ArkModel):
79
allow_caching: bool = Field(description='Allow short lived token caching', default=False)
10+
service: Literal['DPA-DB', 'DPA-RDP'] = Field(description='Which service to get the token info for', default='DPA-DB')

ark_sdk_python/services/sia/ark_sia_api.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ark_sdk_python.services.sia.policies.vm import ArkSIAVMPoliciesService
88
from ark_sdk_python.services.sia.secrets.db import ArkSIADBSecretsService
99
from ark_sdk_python.services.sia.secrets.vm import ArkSIAVMSecretsService
10+
from ark_sdk_python.services.sia.ssh_ca import ArkSIASSHCAService
1011
from ark_sdk_python.services.sia.sso import ArkSIASSOService
1112
from ark_sdk_python.services.sia.workspaces.db import ArkSIADBWorkspaceService
1213
from ark_sdk_python.services.sia.workspaces.targetsets import ArkSIATargetSetsWorkspaceService
@@ -25,6 +26,7 @@ def __init__(self, isp_auth: ArkISPAuth) -> None:
2526
self.__certificates_service = ArkSIACertificatesService(isp_auth)
2627
self.__k8s_service = ArkSIAK8SService(isp_auth)
2728
self.__access_service = ArkSIAAccessService(isp_auth)
29+
self.__ssh_ca_service = ArkSIASSHCAService(isp_auth)
2830

2931
@property
3032
def workspace_db(self) -> ArkSIADBWorkspaceService:
@@ -135,3 +137,13 @@ def k8s(self) -> ArkSIAK8SService:
135137
ArkSIAK8SService: _description_
136138
"""
137139
return self.__k8s_service
140+
141+
@property
142+
def ssh_ca(self) -> ArkSIASSHCAService:
143+
"""
144+
Getter for the SSH CA service
145+
146+
Returns:
147+
ArkDPASSHCAService: _description_
148+
"""
149+
return self.__ssh_ca_service
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from ark_sdk_python.services.sia.ssh_ca.ark_sia_ssh_ca_service import ArkSIASSHCAService
2+
3+
__all__ = ['ArkSIASSHCAService']
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import os
2+
from http import HTTPStatus
3+
from typing import Final
4+
5+
from overrides import overrides
6+
from requests import Response
7+
8+
from ark_sdk_python.auth.ark_isp_auth import ArkISPAuth
9+
from ark_sdk_python.common.isp import ArkISPServiceClient
10+
from ark_sdk_python.models import ArkServiceException
11+
from ark_sdk_python.models.services import ArkServiceConfig
12+
from ark_sdk_python.models.services.sia.ssh_ca import ArkSIAGetSSHPublicKey
13+
from ark_sdk_python.services.ark_service import ArkService
14+
15+
SERVICE_CONFIG: Final[ArkServiceConfig] = ArkServiceConfig(
16+
service_name='sia-ssh-ca', required_authenticator_names=['isp'], optional_authenticator_names=[]
17+
)
18+
19+
# SSH CA Key Rotation
20+
GENERATE_NEW_CA_KEY_API: Final[str] = 'api/public-keys/rotation/generate-new'
21+
DEACTIVATE_PREVIOUS_CA_KEY_API: Final[str] = 'api/public-keys/rotation/deactivate-previous'
22+
REACTIVATE_PREVIOUS_CA_KEY_API: Final[str] = 'api/public-keys/rotation/reactivate-previous'
23+
24+
PUBLIC_KEYS_API: Final[str] = 'api/public-keys'
25+
PUBLIC_KEYS_SCRIPT_API: Final[str] = 'api/public-keys/scripts'
26+
27+
28+
class ArkSIASSHCAService(ArkService):
29+
def __init__(self, isp_auth: ArkISPAuth) -> None:
30+
super().__init__(isp_auth)
31+
self.__isp_auth = isp_auth
32+
self.__client: ArkISPServiceClient = ArkISPServiceClient.from_isp_auth(
33+
isp_auth=self.__isp_auth,
34+
service_name='dpa',
35+
refresh_connection_callback=self.__refresh_sia_auth,
36+
)
37+
38+
def __refresh_sia_auth(self, client: ArkISPServiceClient) -> None:
39+
ArkISPServiceClient.refresh_client(client, self.__isp_auth)
40+
41+
def generate_new_ca(self) -> None:
42+
"""
43+
Generate new SSH CA key version
44+
45+
Raises:
46+
ArkServiceException: _description_
47+
"""
48+
self._logger.info('Generate new CA key version')
49+
resp: Response = self.__client.post(GENERATE_NEW_CA_KEY_API)
50+
if resp.status_code != HTTPStatus.CREATED:
51+
raise ArkServiceException(f'Failed to generate new CA key [{resp.text}] - [{resp.status_code}]')
52+
53+
def deactivate_previous_ca(self) -> None:
54+
"""
55+
Deactivate previous SSH CA key version
56+
57+
Raises:
58+
ArkServiceException: _description_
59+
"""
60+
self._logger.info('Deactivate previous CA key version')
61+
resp: Response = self.__client.post(DEACTIVATE_PREVIOUS_CA_KEY_API)
62+
if resp.status_code != HTTPStatus.OK:
63+
raise ArkServiceException(f'Failed to deactivate previous CA key [{resp.text}] - [{resp.status_code}]')
64+
65+
def reactivate_previous_ca(self) -> None:
66+
"""
67+
Reactivate previous SSH CA key version
68+
69+
Raises:
70+
ArkServiceException: _description_
71+
"""
72+
self._logger.info('Reactivate previous CA key version')
73+
resp: Response = self.__client.post(REACTIVATE_PREVIOUS_CA_KEY_API)
74+
if resp.status_code != HTTPStatus.OK:
75+
raise ArkServiceException(f'Failed to reactivate previous CA key [{resp.text}] - [{resp.status_code}]')
76+
77+
def public_key(self, get_public_key: ArkSIAGetSSHPublicKey) -> str:
78+
"""
79+
Retrieves the public key used for SIA SSH connections trust with customer env
80+
81+
Args:
82+
get_public_key (ArkSIAGetSSHPublicKey): _description_
83+
84+
Raises:
85+
ArkNotSupportedException: _description_
86+
ArkServiceException: _description_
87+
88+
Returns:
89+
str
90+
"""
91+
self._logger.info('Getting public key')
92+
resp: Response = self.__client.get(PUBLIC_KEYS_API)
93+
if resp.status_code == HTTPStatus.OK:
94+
if get_public_key.output_file:
95+
os.makedirs(os.path.dirname(get_public_key.output_file), exist_ok=True)
96+
with open(get_public_key.output_file, 'w', encoding='utf-8') as f:
97+
f.write(resp.text)
98+
return resp.text
99+
raise ArkServiceException(f'Failed to get public key [{resp.text}] - [{resp.status_code}]')
100+
101+
def public_key_script(self, get_public_key: ArkSIAGetSSHPublicKey) -> str:
102+
"""
103+
Retrieves the public key script used for SIA SSH connections trust with customer env
104+
The script can be run to install the public key in needed ssh configuration files
105+
106+
Args:
107+
get_public_key (ArkSIAGetSSHPublicKey): _description_
108+
109+
Raises:
110+
ArkNotSupportedException: _description_
111+
ArkServiceException: _description_
112+
113+
Returns:
114+
str
115+
"""
116+
self._logger.info('Getting public key script')
117+
resp: Response = self.__client.get(
118+
PUBLIC_KEYS_SCRIPT_API,
119+
)
120+
if resp.status_code == HTTPStatus.OK:
121+
if get_public_key.output_file:
122+
os.makedirs(os.path.dirname(get_public_key.output_file), exist_ok=True)
123+
with open(get_public_key.output_file, 'w', encoding='utf-8') as f:
124+
f.write(resp.text)
125+
return resp.text
126+
raise ArkServiceException(f'Failed to get public key script [{resp.text}] - [{resp.status_code}]')
127+
128+
@staticmethod
129+
@overrides
130+
def service_config() -> ArkServiceConfig:
131+
return SERVICE_CONFIG

0 commit comments

Comments
 (0)