strongdm.client

  1# Copyright 2020 StrongDM Inc
  2#
  3# Licensed under the Apache License, Version 2.0 (the "License");
  4# you may not use this file except in compliance with the License.
  5# You may obtain a copy of the License at
  6#
  7#     http://www.apache.org/licenses/LICENSE-2.0
  8#
  9# Unless required by applicable law or agreed to in writing, software
 10# distributed under the License is distributed on an "AS IS" BASIS,
 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12# See the License for the specific language governing permissions and
 13# limitations under the License.
 14#
 15
 16# Code generated by protogen. DO NOT EDIT.
 17
 18import base64
 19import collections
 20import copy
 21import datetime
 22import functools
 23import grpc
 24import hashlib
 25import hmac
 26import random
 27import re
 28import time
 29from . import errors
 30from . import plumbing
 31from . import svc
 32
 33from cryptography.hazmat.primitives.asymmetric import rsa, padding
 34from cryptography.hazmat.primitives import serialization, hashes
 35
 36# These defaults are taken from AWS. Customization of these values
 37# is a future step in the API.
 38DEFAULT_BASE_RETRY_DELAY = 1  # 1 second
 39DEFAULT_MAX_RETRY_DELAY = 120  # 120 seconds
 40DEFAULT_RETRY_FACTOR = 1.6
 41DEFAULT_RETRY_JITTER = 0.2
 42API_VERSION = '2025-04-14'
 43USER_AGENT = 'strongdm-sdk-python/15.44.0'
 44
 45method_regexp = re.compile(r'\W+')
 46
 47
 48class _ClientCallDetails(
 49        collections.namedtuple(
 50            "_ClientCallDetails",
 51            ("method", "timeout", "metadata", "credentials")),
 52        grpc.ClientCallDetails,
 53):
 54    """ _ClientCallDetails is used to override some of the attributes of the client_call_details in the interceptors"""
 55    pass
 56
 57
 58class _EncryptionInterceptor(grpc.UnaryUnaryClientInterceptor):
 59    """ _EncryptionInterceptor is used to add transparent encryption/decryption support for managed secrets"""
 60    def __init__(self, client):
 61        self.client = client
 62        self.public_key_cache = {}
 63
 64    def intercept_unary_unary(self, continuation, client_call_details,
 65                              request):
 66        method = method_regexp.sub("_", client_call_details.method.lower())
 67        callback = getattr(self, method, None)
 68        if callback is not None:
 69            return callback(continuation, client_call_details, request)
 70        return continuation(client_call_details, request)
 71
 72    @functools.cached_property
 73    def private_key(self):
 74        return rsa.generate_private_key(
 75            public_exponent=65537,
 76            key_size=4096,
 77        )
 78
 79    def _encrypt_secret(self, method, continuation, client_call_details,
 80                        request):
 81        secret = request.managed_secret
 82        if len(secret.value) != 0:
 83            if secret.secret_engine_id not in self.public_key_cache:
 84                try:
 85                    # fetch secret engine details to fill up self.public_key_cache
 86                    # if it fails the call to create/update will fail as well
 87                    self.client.secret_engines.get(secret.secret_engine_id)
 88                except errors.RPCError:
 89                    pass
 90            key = self.public_key_cache.get(secret.secret_engine_id)
 91            if key is not None:
 92                encrypted = key.encrypt(
 93                    secret.value,
 94                    padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
 95                                 algorithm=hashes.SHA256(),
 96                                 label=None))
 97                secret.value = encrypted
 98            client_call_details = _ClientCallDetails(
 99                method=client_call_details.method,
100                timeout=client_call_details.timeout,
101                metadata=self.client.get_metadata(method, request),
102                credentials=client_call_details.credentials)
103        return continuation(client_call_details, request)
104
105    def _v1_managedsecrets_create(self, continuation, client_call_details,
106                                  request):
107        return self._encrypt_secret("ManagedSecrets.Create", continuation,
108                                    client_call_details, request)
109
110    def _v1_managedsecrets_update(self, continuation, client_call_details,
111                                  request):
112        return self._encrypt_secret("ManagedSecrets.Update", continuation,
113                                    client_call_details, request)
114
115    def _v1_managedsecrets_retrieve(self, continuation, client_call_details,
116                                    request):
117        if len(request.public_key) != 0:
118            return continuation(client_call_details, request)
119
120        privKey = self.private_key
121        request.public_key = privKey.public_key().public_bytes(
122            serialization.Encoding.PEM,
123            serialization.PublicFormat.SubjectPublicKeyInfo)
124        client_call_details = _ClientCallDetails(
125            method=client_call_details.method,
126            timeout=client_call_details.timeout,
127            metadata=self.client.get_metadata("ManagedSecrets.Retrieve",
128                                              request),
129            credentials=client_call_details.credentials)
130        resp = continuation(client_call_details, request)
131        if resp.code() != grpc.StatusCode.OK:
132            return resp
133        result = resp.result()
134        plaintext = privKey.decrypt(
135            result.managed_secret.value,
136            padding.OAEP(
137                mgf=padding.MGF1(algorithm=hashes.SHA256()),
138                algorithm=hashes.SHA256(),
139                label=None,
140            ))
141        result.managed_secret.value = plaintext
142        return resp
143
144    def _v1_secretengines_get(self, continuation, client_call_details,
145                              request):
146        response = continuation(client_call_details, request)
147        if response.code() != grpc.StatusCode.OK:
148            return response
149        result = response.result()
150        engine = plumbing.convert_secret_engine_to_porcelain(
151            result.secret_engine)
152        engineKey = serialization.load_pem_public_key(engine.public_key)
153        self.public_key_cache[engine.id] = engineKey
154        return response
155
156    def _v1_secretengines_list(self, continuation, client_call_details,
157                               request):
158        response = continuation(client_call_details, request)
159        if response.code() != grpc.StatusCode.OK:
160            return response
161        result = response.result()
162        for plumbing_engine in result.secret_engines:
163            engine = plumbing.convert_secret_engine_to_porcelain(
164                plumbing_engine)
165            engineKey = serialization.load_pem_public_key(engine.public_key)
166            self.public_key_cache[engine.id] = engineKey
167        return response
168
169
170class Client:
171    '''Client interacts with the strongDM API.'''
172    def __init__(self,
173                 api_access_key,
174                 api_secret,
175                 host='app.strongdm.com:443',
176                 insecure=False,
177                 retry_rate_limit_errors=True,
178                 page_limit=0):
179        '''
180        Create a new Client.
181
182        - api_access_key: the access key to authenticate with strongDM
183        - api_secret: the secret key to authenticate with strongDM
184        '''
185        self.api_access_key = api_access_key.strip()
186        self.api_secret = base64.b64decode(api_secret.strip())
187        self.base_retry_delay = DEFAULT_BASE_RETRY_DELAY
188        self.max_retry_delay = DEFAULT_MAX_RETRY_DELAY
189        self.retry_factor = DEFAULT_RETRY_FACTOR
190        self.retry_jitter = DEFAULT_RETRY_JITTER
191        self.retry_rate_limit_errors = retry_rate_limit_errors
192        self.snapshot_datetime = None
193        self.page_limit = page_limit
194
195        try:
196            if insecure:
197                channel = grpc.insecure_channel(host)
198            else:
199                creds = grpc.ssl_channel_credentials()
200                channel = grpc.secure_channel(host, creds)
201        except Exception as e:
202            raise plumbing.convert_error_to_porcelain(e) from e
203        channel = grpc.intercept_channel(channel, _EncryptionInterceptor(self))
204        self.channel = channel
205        self.access_requests = svc.AccessRequests(channel, self)
206        '''
207         AccessRequests are requests for access to a resource that may match a Workflow.
208
209        See `strongdm.svc.AccessRequests`.
210        '''
211        self.access_request_events_history = svc.AccessRequestEventsHistory(
212            channel, self)
213        '''
214         AccessRequestEventsHistory provides records of all changes to the state of an AccessRequest.
215
216        See `strongdm.svc.AccessRequestEventsHistory`.
217        '''
218        self.access_requests_history = svc.AccessRequestsHistory(channel, self)
219        '''
220         AccessRequestsHistory provides records of all changes to the state of an AccessRequest.
221
222        See `strongdm.svc.AccessRequestsHistory`.
223        '''
224        self.account_attachments = svc.AccountAttachments(channel, self)
225        '''
226         AccountAttachments assign an account to a role.
227
228        See `strongdm.svc.AccountAttachments`.
229        '''
230        self.account_attachments_history = svc.AccountAttachmentsHistory(
231            channel, self)
232        '''
233         AccountAttachmentsHistory records all changes to the state of an AccountAttachment.
234
235        See `strongdm.svc.AccountAttachmentsHistory`.
236        '''
237        self.account_grants = svc.AccountGrants(channel, self)
238        '''
239         AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
240
241        See `strongdm.svc.AccountGrants`.
242        '''
243        self.account_grants_history = svc.AccountGrantsHistory(channel, self)
244        '''
245         AccountGrantsHistory records all changes to the state of an AccountGrant.
246
247        See `strongdm.svc.AccountGrantsHistory`.
248        '''
249        self.account_permissions = svc.AccountPermissions(channel, self)
250        '''
251         AccountPermissions records the granular permissions accounts have, allowing them to execute
252         relevant commands via StrongDM's APIs.
253
254        See `strongdm.svc.AccountPermissions`.
255        '''
256        self.account_resources = svc.AccountResources(channel, self)
257        '''
258         AccountResources enumerates the resources to which accounts have access.
259         The AccountResources service is read-only.
260
261        See `strongdm.svc.AccountResources`.
262        '''
263        self.account_resources_history = svc.AccountResourcesHistory(
264            channel, self)
265        '''
266         AccountResourcesHistory records all changes to the state of a AccountResource.
267
268        See `strongdm.svc.AccountResourcesHistory`.
269        '''
270        self.accounts = svc.Accounts(channel, self)
271        '''
272         Accounts are users that have access to strongDM. There are two types of accounts:
273         1. **Users:** humans who are authenticated through username and password or SSO.
274         2. **Service Accounts:** machines that are authenticated using a service token.
275         3. **Tokens** are access keys with permissions that can be used for authentication.
276
277        See `strongdm.svc.Accounts`.
278        '''
279        self.accounts_groups = svc.AccountsGroups(channel, self)
280        '''
281         An AccountGroup links an account and a group.
282
283        See `strongdm.svc.AccountsGroups`.
284        '''
285        self.accounts_groups_history = svc.AccountsGroupsHistory(channel, self)
286        '''
287         AccountsGroupsHistory records all changes to the state of an AccountGroup.
288
289        See `strongdm.svc.AccountsGroupsHistory`.
290        '''
291        self.accounts_history = svc.AccountsHistory(channel, self)
292        '''
293         AccountsHistory records all changes to the state of an Account.
294
295        See `strongdm.svc.AccountsHistory`.
296        '''
297        self.activities = svc.Activities(channel, self)
298        '''
299         An Activity is a record of an action taken against a strongDM deployment, e.g.
300         a user creation, resource deletion, sso configuration change, etc. The Activities
301         service is read-only.
302
303        See `strongdm.svc.Activities`.
304        '''
305        self.approval_workflow_approvers = svc.ApprovalWorkflowApprovers(
306            channel, self)
307        '''
308         ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep
309
310        See `strongdm.svc.ApprovalWorkflowApprovers`.
311        '''
312        self.approval_workflow_approvers_history = svc.ApprovalWorkflowApproversHistory(
313            channel, self)
314        '''
315         ApprovalWorkflowApproversHistory records all changes to the state of an ApprovalWorkflowApprover.
316
317        See `strongdm.svc.ApprovalWorkflowApproversHistory`.
318        '''
319        self.approval_workflow_steps = svc.ApprovalWorkflowSteps(channel, self)
320        '''
321         ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow
322
323        See `strongdm.svc.ApprovalWorkflowSteps`.
324        '''
325        self.approval_workflow_steps_history = svc.ApprovalWorkflowStepsHistory(
326            channel, self)
327        '''
328         ApprovalWorkflowStepsHistory records all changes to the state of an ApprovalWorkflowStep.
329
330        See `strongdm.svc.ApprovalWorkflowStepsHistory`.
331        '''
332        self.approval_workflows = svc.ApprovalWorkflows(channel, self)
333        '''
334         ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized
335         approvers and be approved or denied.
336
337        See `strongdm.svc.ApprovalWorkflows`.
338        '''
339        self.approval_workflows_history = svc.ApprovalWorkflowsHistory(
340            channel, self)
341        '''
342         ApprovalWorkflowsHistory records all changes to the state of an ApprovalWorkflow.
343
344        See `strongdm.svc.ApprovalWorkflowsHistory`.
345        '''
346        self.control_panel = svc.ControlPanel(channel, self)
347        '''
348         ControlPanel contains all administrative controls.
349
350        See `strongdm.svc.ControlPanel`.
351        '''
352        self.discovery_connectors = svc.DiscoveryConnectors(channel, self)
353        '''
354         A Discovery Connector is a configuration object for performing Resource
355         Scans in remote systems such as AWS, GCP, Azure, and other systems.
356
357        See `strongdm.svc.DiscoveryConnectors`.
358        '''
359        self.roles = svc.Roles(channel, self)
360        '''
361         A Role has a list of access rules which determine which Resources the members
362         of the Role have access to. An Account can be a member of multiple Roles via
363         AccountAttachments.
364
365        See `strongdm.svc.Roles`.
366        '''
367        self.groups = svc.Groups(channel, self)
368        '''
369         A Group is a set of principals.
370
371        See `strongdm.svc.Groups`.
372        '''
373        self.groups_history = svc.GroupsHistory(channel, self)
374        '''
375         GroupsHistory records all changes to the state of a Group.
376
377        See `strongdm.svc.GroupsHistory`.
378        '''
379        self.groups_roles = svc.GroupsRoles(channel, self)
380        '''
381         A GroupRole is an assignment of a Group to a Role.
382
383        See `strongdm.svc.GroupsRoles`.
384        '''
385        self.groups_roles_history = svc.GroupsRolesHistory(channel, self)
386        '''
387         GroupsRolesHistory records all changes to the state of a GroupRole.
388
389        See `strongdm.svc.GroupsRolesHistory`.
390        '''
391        self.health_checks = svc.HealthChecks(channel, self)
392        '''
393         HealthChecks lists the last healthcheck between each node and resource.
394         Note the unconventional capitalization here is to prevent having a collision with GRPC
395
396        See `strongdm.svc.HealthChecks`.
397        '''
398        self.identity_aliases = svc.IdentityAliases(channel, self)
399        '''
400         IdentityAliases assign an alias to an account within an IdentitySet.
401         The alias is used as the username when connecting to a identity supported resource.
402
403        See `strongdm.svc.IdentityAliases`.
404        '''
405        self.identity_aliases_history = svc.IdentityAliasesHistory(
406            channel, self)
407        '''
408         IdentityAliasesHistory records all changes to the state of a IdentityAlias.
409
410        See `strongdm.svc.IdentityAliasesHistory`.
411        '''
412        self.identity_sets = svc.IdentitySets(channel, self)
413        '''
414         A IdentitySet is a named grouping of Identity Aliases for Accounts.
415         An Account's relationship to a IdentitySet is defined via IdentityAlias objects.
416
417        See `strongdm.svc.IdentitySets`.
418        '''
419        self.identity_sets_history = svc.IdentitySetsHistory(channel, self)
420        '''
421         IdentitySetsHistory records all changes to the state of a IdentitySet.
422
423        See `strongdm.svc.IdentitySetsHistory`.
424        '''
425        self.managed_secrets = svc.ManagedSecrets(channel, self)
426        '''
427         ManagedSecret is a private vertical for creating, reading, updating,
428         deleting, listing and rotating the managed secrets in the secrets engines as
429         an authenticated user.
430
431        See `strongdm.svc.ManagedSecrets`.
432        '''
433        self.nodes = svc.Nodes(channel, self)
434        '''
435         Nodes make up the StrongDM network, and allow your users to connect securely to your resources.
436         There are three types of nodes:
437         1. **Relay:** creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
438         2. **Gateway:** a relay that also listens for connections from StrongDM clients
439         3. **Proxy Cluster:** a cluster of workers that together mediate access from clients to resources
440
441        See `strongdm.svc.Nodes`.
442        '''
443        self.nodes_history = svc.NodesHistory(channel, self)
444        '''
445         NodesHistory records all changes to the state of a Node.
446
447        See `strongdm.svc.NodesHistory`.
448        '''
449        self.organization_history = svc.OrganizationHistory(channel, self)
450        '''
451         OrganizationHistory records all changes to the state of an Organization.
452
453        See `strongdm.svc.OrganizationHistory`.
454        '''
455        self.peering_group_nodes = svc.PeeringGroupNodes(channel, self)
456        '''
457         PeeringGroupNodes provides the building blocks necessary to obtain attach a node to a peering group.
458
459        See `strongdm.svc.PeeringGroupNodes`.
460        '''
461        self.peering_group_peers = svc.PeeringGroupPeers(channel, self)
462        '''
463         PeeringGroupPeers provides the building blocks necessary to link two peering groups.
464
465        See `strongdm.svc.PeeringGroupPeers`.
466        '''
467        self.peering_group_resources = svc.PeeringGroupResources(channel, self)
468        '''
469         PeeringGroupResources provides the building blocks necessary to obtain attach a resource to a peering group.
470
471        See `strongdm.svc.PeeringGroupResources`.
472        '''
473        self.peering_groups = svc.PeeringGroups(channel, self)
474        '''
475         PeeringGroups provides the building blocks necessary to obtain explicit network topology and routing.
476
477        See `strongdm.svc.PeeringGroups`.
478        '''
479        self.policies = svc.Policies(channel, self)
480        '''
481         Policies are the collection of one or more statements that enforce fine-grained access
482         control for the users of an organization.
483
484        See `strongdm.svc.Policies`.
485        '''
486        self.policies_history = svc.PoliciesHistory(channel, self)
487        '''
488         PoliciesHistory records all changes to the state of a Policy.
489
490        See `strongdm.svc.PoliciesHistory`.
491        '''
492        self.proxy_cluster_keys = svc.ProxyClusterKeys(channel, self)
493        '''
494         Proxy Cluster Keys are authentication keys for all proxies within a cluster.
495         The proxies within a cluster share the same key. One cluster can have
496         multiple keys in order to facilitate key rotation.
497
498        See `strongdm.svc.ProxyClusterKeys`.
499        '''
500        self.queries = svc.Queries(channel, self)
501        '''
502         A Query is a record of a single client request to a resource, such as a SQL query.
503         Long-running SSH, RDP, or Kubernetes interactive sessions also count as queries.
504         The Queries service is read-only.
505
506        See `strongdm.svc.Queries`.
507        '''
508        self.remote_identities = svc.RemoteIdentities(channel, self)
509        '''
510         RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
511
512        See `strongdm.svc.RemoteIdentities`.
513        '''
514        self.remote_identities_history = svc.RemoteIdentitiesHistory(
515            channel, self)
516        '''
517         RemoteIdentitiesHistory records all changes to the state of a RemoteIdentity.
518
519        See `strongdm.svc.RemoteIdentitiesHistory`.
520        '''
521        self.remote_identity_groups = svc.RemoteIdentityGroups(channel, self)
522        '''
523         A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
524         An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
525
526        See `strongdm.svc.RemoteIdentityGroups`.
527        '''
528        self.remote_identity_groups_history = svc.RemoteIdentityGroupsHistory(
529            channel, self)
530        '''
531         RemoteIdentityGroupsHistory records all changes to the state of a RemoteIdentityGroup.
532
533        See `strongdm.svc.RemoteIdentityGroupsHistory`.
534        '''
535        self.replays = svc.Replays(channel, self)
536        '''
537         A Replay captures the data transferred over a long-running SSH, RDP, or Kubernetes interactive session
538         (otherwise referred to as a query). The Replays service is read-only.
539
540        See `strongdm.svc.Replays`.
541        '''
542        self.resources = svc.Resources(channel, self)
543        '''
544         Resources are databases, servers, clusters, websites, or clouds that strongDM
545         delegates access to.
546
547        See `strongdm.svc.Resources`.
548        '''
549        self.resources_history = svc.ResourcesHistory(channel, self)
550        '''
551         ResourcesHistory records all changes to the state of a Resource.
552
553        See `strongdm.svc.ResourcesHistory`.
554        '''
555        self.role_resources = svc.RoleResources(channel, self)
556        '''
557         RoleResources enumerates the resources to which roles have access.
558         The RoleResources service is read-only.
559
560        See `strongdm.svc.RoleResources`.
561        '''
562        self.role_resources_history = svc.RoleResourcesHistory(channel, self)
563        '''
564         RoleResourcesHistory records all changes to the state of a RoleResource.
565
566        See `strongdm.svc.RoleResourcesHistory`.
567        '''
568        self.roles_history = svc.RolesHistory(channel, self)
569        '''
570         RolesHistory records all changes to the state of a Role.
571
572        See `strongdm.svc.RolesHistory`.
573        '''
574        self.secret_stores = svc.SecretStores(channel, self)
575        '''
576         SecretStores are servers where resource secrets (passwords, keys) are stored.
577
578        See `strongdm.svc.SecretStores`.
579        '''
580        self.secret_engines = svc.SecretEngines(channel, self)
581        '''
582
583
584        See `strongdm.svc.SecretEngines`.
585        '''
586        self.secret_store_healths = svc.SecretStoreHealths(channel, self)
587        '''
588         SecretStoreHealths exposes health states for secret stores.
589
590        See `strongdm.svc.SecretStoreHealths`.
591        '''
592        self.secret_stores_history = svc.SecretStoresHistory(channel, self)
593        '''
594         SecretStoresHistory records all changes to the state of a SecretStore.
595
596        See `strongdm.svc.SecretStoresHistory`.
597        '''
598        self.workflow_approvers = svc.WorkflowApprovers(channel, self)
599        '''
600         WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.
601
602        See `strongdm.svc.WorkflowApprovers`.
603        '''
604        self.workflow_approvers_history = svc.WorkflowApproversHistory(
605            channel, self)
606        '''
607         WorkflowApproversHistory provides records of all changes to the state of a WorkflowApprover.
608
609        See `strongdm.svc.WorkflowApproversHistory`.
610        '''
611        self.workflow_roles = svc.WorkflowRoles(channel, self)
612        '''
613         WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of
614         to request access to a resource via the workflow.
615
616        See `strongdm.svc.WorkflowRoles`.
617        '''
618        self.workflow_roles_history = svc.WorkflowRolesHistory(channel, self)
619        '''
620         WorkflowRolesHistory provides records of all changes to the state of a WorkflowRole
621
622        See `strongdm.svc.WorkflowRolesHistory`.
623        '''
624        self.workflows = svc.Workflows(channel, self)
625        '''
626         Workflows are the collection of rules that define the resources to which access can be requested,
627         the users that can request that access, and the mechanism for approving those requests which can either
628         be automatic approval or a set of users authorized to approve the requests.
629
630        See `strongdm.svc.Workflows`.
631        '''
632        self.workflows_history = svc.WorkflowsHistory(channel, self)
633        '''
634         WorkflowsHistory provides records of all changes to the state of a Workflow.
635
636        See `strongdm.svc.WorkflowsHistory`.
637        '''
638
639    def close(self):
640        '''Closes this Client and releases all resources held by it.
641
642        Closing the Client will immediately terminate all RPCs active with the
643        Client and it is not valid to invoke new RPCs with the Client.
644
645        This method is idempotent.
646        '''
647        self.channel.close()
648
649    def get_metadata(self, method_name, req):
650        return [
651            ('x-sdm-authentication', self.api_access_key),
652            ('x-sdm-signature', self.sign(method_name,
653                                          req.SerializeToString())),
654            ('x-sdm-api-version', API_VERSION),
655            ('x-sdm-user-agent', USER_AGENT),
656        ]
657
658    def sign(self, method_name, request_bytes):
659        def hmac_digest(key, msg_byte_string):
660            return hmac.new(key, msg=msg_byte_string,
661                            digestmod=hashlib.sha256).digest()
662
663        current_utc_date = datetime.datetime.now(
664            datetime.timezone.utc).strftime('%Y-%m-%d')
665        signing_key = hmac_digest(self.api_secret, current_utc_date.encode())
666        signing_key = hmac_digest(signing_key, b'sdm_api_v1')
667
668        hash = hashlib.sha256()
669
670        hash.update(method_name.encode())
671        hash.update(b'\n')
672        hash.update(request_bytes)
673
674        return base64.b64encode(hmac_digest(signing_key, hash.digest()))
675
676    def exponentialBackoff(self, retries, deadline=None):
677        def applyDeadline(delay, deadline):
678            if deadline is None:
679                return delay
680            remaining = deadline - time.time()
681            if remaining < 0:
682                return 0
683            return min(delay, remaining)
684
685        if retries == 0:
686            return applyDeadline(self.base_retry_delay, deadline)
687
688        backoff, max_delay = self.base_retry_delay, self.max_retry_delay
689        while backoff < max_delay and retries > 0:
690            backoff *= self.retry_factor
691            retries -= 1
692
693        if backoff > max_delay:
694            backoff = max_delay
695
696        # Randomize backoff delays so that if a cluster of requests start at
697        # the same time, they won't operate in lockstep.
698        backoff *= 1 + self.retry_jitter * (random.random() * 2 - 1)
699        if backoff < 0:
700            return 0
701
702        return applyDeadline(backoff, deadline)
703
704    def shouldRetry(self, retries, err, deadline=None):
705        # Check if we've passed the deadline
706        if deadline is not None and time.time() >= deadline:
707            return False
708
709        if not isinstance(err, grpc.RpcError):
710            return False
711
712        if self.retry_rate_limit_errors and err.code(
713        ) == grpc.StatusCode.RESOURCE_EXHAUSTED:
714            return True
715
716        return retries <= 3 and (err.code() == grpc.StatusCode.INTERNAL
717                                 or err.code() == grpc.StatusCode.UNAVAILABLE)
718
719    def snapshot_at(self, snapshot_datetime):
720        '''
721        Constructs a read-only client that will provide historical data from the provided timestamp.
722
723        See `SnapshotClient`.
724        '''
725        client = copy.copy(self)
726        client.snapshot_datetime = snapshot_datetime
727        client.access_requests = svc.AccessRequests(client.channel, client)
728        client.account_attachments = svc.AccountAttachments(
729            client.channel, client)
730        client.account_grants = svc.AccountGrants(client.channel, client)
731        client.account_permissions = svc.AccountPermissions(
732            client.channel, client)
733        client.account_resources = svc.AccountResources(client.channel, client)
734        client.accounts = svc.Accounts(client.channel, client)
735        client.accounts_groups = svc.AccountsGroups(client.channel, client)
736        client.approval_workflow_approvers = svc.ApprovalWorkflowApprovers(
737            client.channel, client)
738        client.approval_workflow_steps = svc.ApprovalWorkflowSteps(
739            client.channel, client)
740        client.approval_workflows = svc.ApprovalWorkflows(
741            client.channel, client)
742        client.discovery_connectors = svc.DiscoveryConnectors(
743            client.channel, client)
744        client.roles = svc.Roles(client.channel, client)
745        client.groups = svc.Groups(client.channel, client)
746        client.groups_roles = svc.GroupsRoles(client.channel, client)
747        client.identity_aliases = svc.IdentityAliases(client.channel, client)
748        client.identity_sets = svc.IdentitySets(client.channel, client)
749        client.nodes = svc.Nodes(client.channel, client)
750        client.policies = svc.Policies(client.channel, client)
751        client.proxy_cluster_keys = svc.ProxyClusterKeys(
752            client.channel, client)
753        client.remote_identities = svc.RemoteIdentities(client.channel, client)
754        client.remote_identity_groups = svc.RemoteIdentityGroups(
755            client.channel, client)
756        client.resources = svc.Resources(client.channel, client)
757        client.role_resources = svc.RoleResources(client.channel, client)
758        client.secret_stores = svc.SecretStores(client.channel, client)
759        client.workflow_approvers = svc.WorkflowApprovers(
760            client.channel, client)
761        client.workflow_roles = svc.WorkflowRoles(client.channel, client)
762        client.workflows = svc.Workflows(client.channel, client)
763        return SnapshotClient(client)
764
765
766class SnapshotClient:
767    '''SnapshotClient exposes methods to query historical records at a provided timestamp.'''
768    def __init__(self, client):
769        self.access_requests = svc.SnapshotAccessRequests(
770            client.access_requests)
771        '''
772         AccessRequests are requests for access to a resource that may match a Workflow.
773
774        See `strongdm.svc.SnapshotAccessRequests`.
775        '''
776        self.account_attachments = svc.SnapshotAccountAttachments(
777            client.account_attachments)
778        '''
779         AccountAttachments assign an account to a role.
780
781        See `strongdm.svc.SnapshotAccountAttachments`.
782        '''
783        self.account_grants = svc.SnapshotAccountGrants(client.account_grants)
784        '''
785         AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
786
787        See `strongdm.svc.SnapshotAccountGrants`.
788        '''
789        self.account_permissions = svc.SnapshotAccountPermissions(
790            client.account_permissions)
791        '''
792         AccountPermissions records the granular permissions accounts have, allowing them to execute
793         relevant commands via StrongDM's APIs.
794
795        See `strongdm.svc.SnapshotAccountPermissions`.
796        '''
797        self.account_resources = svc.SnapshotAccountResources(
798            client.account_resources)
799        '''
800         AccountResources enumerates the resources to which accounts have access.
801         The AccountResources service is read-only.
802
803        See `strongdm.svc.SnapshotAccountResources`.
804        '''
805        self.accounts = svc.SnapshotAccounts(client.accounts)
806        '''
807         Accounts are users that have access to strongDM. There are two types of accounts:
808         1. **Users:** humans who are authenticated through username and password or SSO.
809         2. **Service Accounts:** machines that are authenticated using a service token.
810         3. **Tokens** are access keys with permissions that can be used for authentication.
811
812        See `strongdm.svc.SnapshotAccounts`.
813        '''
814        self.accounts_groups = svc.SnapshotAccountsGroups(
815            client.accounts_groups)
816        '''
817         An AccountGroup links an account and a group.
818
819        See `strongdm.svc.SnapshotAccountsGroups`.
820        '''
821        self.approval_workflow_approvers = svc.SnapshotApprovalWorkflowApprovers(
822            client.approval_workflow_approvers)
823        '''
824         ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep
825
826        See `strongdm.svc.SnapshotApprovalWorkflowApprovers`.
827        '''
828        self.approval_workflow_steps = svc.SnapshotApprovalWorkflowSteps(
829            client.approval_workflow_steps)
830        '''
831         ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow
832
833        See `strongdm.svc.SnapshotApprovalWorkflowSteps`.
834        '''
835        self.approval_workflows = svc.SnapshotApprovalWorkflows(
836            client.approval_workflows)
837        '''
838         ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized
839         approvers and be approved or denied.
840
841        See `strongdm.svc.SnapshotApprovalWorkflows`.
842        '''
843        self.discovery_connectors = svc.SnapshotDiscoveryConnectors(
844            client.discovery_connectors)
845        '''
846         A Discovery Connector is a configuration object for performing Resource
847         Scans in remote systems such as AWS, GCP, Azure, and other systems.
848
849        See `strongdm.svc.SnapshotDiscoveryConnectors`.
850        '''
851        self.roles = svc.SnapshotRoles(client.roles)
852        '''
853         A Role has a list of access rules which determine which Resources the members
854         of the Role have access to. An Account can be a member of multiple Roles via
855         AccountAttachments.
856
857        See `strongdm.svc.SnapshotRoles`.
858        '''
859        self.groups = svc.SnapshotGroups(client.groups)
860        '''
861         A Group is a set of principals.
862
863        See `strongdm.svc.SnapshotGroups`.
864        '''
865        self.groups_roles = svc.SnapshotGroupsRoles(client.groups_roles)
866        '''
867         A GroupRole is an assignment of a Group to a Role.
868
869        See `strongdm.svc.SnapshotGroupsRoles`.
870        '''
871        self.identity_aliases = svc.SnapshotIdentityAliases(
872            client.identity_aliases)
873        '''
874         IdentityAliases assign an alias to an account within an IdentitySet.
875         The alias is used as the username when connecting to a identity supported resource.
876
877        See `strongdm.svc.SnapshotIdentityAliases`.
878        '''
879        self.identity_sets = svc.SnapshotIdentitySets(client.identity_sets)
880        '''
881         A IdentitySet is a named grouping of Identity Aliases for Accounts.
882         An Account's relationship to a IdentitySet is defined via IdentityAlias objects.
883
884        See `strongdm.svc.SnapshotIdentitySets`.
885        '''
886        self.nodes = svc.SnapshotNodes(client.nodes)
887        '''
888         Nodes make up the StrongDM network, and allow your users to connect securely to your resources.
889         There are three types of nodes:
890         1. **Relay:** creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
891         2. **Gateway:** a relay that also listens for connections from StrongDM clients
892         3. **Proxy Cluster:** a cluster of workers that together mediate access from clients to resources
893
894        See `strongdm.svc.SnapshotNodes`.
895        '''
896        self.policies = svc.SnapshotPolicies(client.policies)
897        '''
898         Policies are the collection of one or more statements that enforce fine-grained access
899         control for the users of an organization.
900
901        See `strongdm.svc.SnapshotPolicies`.
902        '''
903        self.proxy_cluster_keys = svc.SnapshotProxyClusterKeys(
904            client.proxy_cluster_keys)
905        '''
906         Proxy Cluster Keys are authentication keys for all proxies within a cluster.
907         The proxies within a cluster share the same key. One cluster can have
908         multiple keys in order to facilitate key rotation.
909
910        See `strongdm.svc.SnapshotProxyClusterKeys`.
911        '''
912        self.remote_identities = svc.SnapshotRemoteIdentities(
913            client.remote_identities)
914        '''
915         RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
916
917        See `strongdm.svc.SnapshotRemoteIdentities`.
918        '''
919        self.remote_identity_groups = svc.SnapshotRemoteIdentityGroups(
920            client.remote_identity_groups)
921        '''
922         A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
923         An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
924
925        See `strongdm.svc.SnapshotRemoteIdentityGroups`.
926        '''
927        self.resources = svc.SnapshotResources(client.resources)
928        '''
929         Resources are databases, servers, clusters, websites, or clouds that strongDM
930         delegates access to.
931
932        See `strongdm.svc.SnapshotResources`.
933        '''
934        self.role_resources = svc.SnapshotRoleResources(client.role_resources)
935        '''
936         RoleResources enumerates the resources to which roles have access.
937         The RoleResources service is read-only.
938
939        See `strongdm.svc.SnapshotRoleResources`.
940        '''
941        self.secret_stores = svc.SnapshotSecretStores(client.secret_stores)
942        '''
943         SecretStores are servers where resource secrets (passwords, keys) are stored.
944
945        See `strongdm.svc.SnapshotSecretStores`.
946        '''
947        self.workflow_approvers = svc.SnapshotWorkflowApprovers(
948            client.workflow_approvers)
949        '''
950         WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.
951
952        See `strongdm.svc.SnapshotWorkflowApprovers`.
953        '''
954        self.workflow_roles = svc.SnapshotWorkflowRoles(client.workflow_roles)
955        '''
956         WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of
957         to request access to a resource via the workflow.
958
959        See `strongdm.svc.SnapshotWorkflowRoles`.
960        '''
961        self.workflows = svc.SnapshotWorkflows(client.workflows)
962        '''
963         Workflows are the collection of rules that define the resources to which access can be requested,
964         the users that can request that access, and the mechanism for approving those requests which can either
965         be automatic approval or a set of users authorized to approve the requests.
966
967        See `strongdm.svc.SnapshotWorkflows`.
968        '''
class Client:
171class Client:
172    '''Client interacts with the strongDM API.'''
173    def __init__(self,
174                 api_access_key,
175                 api_secret,
176                 host='app.strongdm.com:443',
177                 insecure=False,
178                 retry_rate_limit_errors=True,
179                 page_limit=0):
180        '''
181        Create a new Client.
182
183        - api_access_key: the access key to authenticate with strongDM
184        - api_secret: the secret key to authenticate with strongDM
185        '''
186        self.api_access_key = api_access_key.strip()
187        self.api_secret = base64.b64decode(api_secret.strip())
188        self.base_retry_delay = DEFAULT_BASE_RETRY_DELAY
189        self.max_retry_delay = DEFAULT_MAX_RETRY_DELAY
190        self.retry_factor = DEFAULT_RETRY_FACTOR
191        self.retry_jitter = DEFAULT_RETRY_JITTER
192        self.retry_rate_limit_errors = retry_rate_limit_errors
193        self.snapshot_datetime = None
194        self.page_limit = page_limit
195
196        try:
197            if insecure:
198                channel = grpc.insecure_channel(host)
199            else:
200                creds = grpc.ssl_channel_credentials()
201                channel = grpc.secure_channel(host, creds)
202        except Exception as e:
203            raise plumbing.convert_error_to_porcelain(e) from e
204        channel = grpc.intercept_channel(channel, _EncryptionInterceptor(self))
205        self.channel = channel
206        self.access_requests = svc.AccessRequests(channel, self)
207        '''
208         AccessRequests are requests for access to a resource that may match a Workflow.
209
210        See `strongdm.svc.AccessRequests`.
211        '''
212        self.access_request_events_history = svc.AccessRequestEventsHistory(
213            channel, self)
214        '''
215         AccessRequestEventsHistory provides records of all changes to the state of an AccessRequest.
216
217        See `strongdm.svc.AccessRequestEventsHistory`.
218        '''
219        self.access_requests_history = svc.AccessRequestsHistory(channel, self)
220        '''
221         AccessRequestsHistory provides records of all changes to the state of an AccessRequest.
222
223        See `strongdm.svc.AccessRequestsHistory`.
224        '''
225        self.account_attachments = svc.AccountAttachments(channel, self)
226        '''
227         AccountAttachments assign an account to a role.
228
229        See `strongdm.svc.AccountAttachments`.
230        '''
231        self.account_attachments_history = svc.AccountAttachmentsHistory(
232            channel, self)
233        '''
234         AccountAttachmentsHistory records all changes to the state of an AccountAttachment.
235
236        See `strongdm.svc.AccountAttachmentsHistory`.
237        '''
238        self.account_grants = svc.AccountGrants(channel, self)
239        '''
240         AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
241
242        See `strongdm.svc.AccountGrants`.
243        '''
244        self.account_grants_history = svc.AccountGrantsHistory(channel, self)
245        '''
246         AccountGrantsHistory records all changes to the state of an AccountGrant.
247
248        See `strongdm.svc.AccountGrantsHistory`.
249        '''
250        self.account_permissions = svc.AccountPermissions(channel, self)
251        '''
252         AccountPermissions records the granular permissions accounts have, allowing them to execute
253         relevant commands via StrongDM's APIs.
254
255        See `strongdm.svc.AccountPermissions`.
256        '''
257        self.account_resources = svc.AccountResources(channel, self)
258        '''
259         AccountResources enumerates the resources to which accounts have access.
260         The AccountResources service is read-only.
261
262        See `strongdm.svc.AccountResources`.
263        '''
264        self.account_resources_history = svc.AccountResourcesHistory(
265            channel, self)
266        '''
267         AccountResourcesHistory records all changes to the state of a AccountResource.
268
269        See `strongdm.svc.AccountResourcesHistory`.
270        '''
271        self.accounts = svc.Accounts(channel, self)
272        '''
273         Accounts are users that have access to strongDM. There are two types of accounts:
274         1. **Users:** humans who are authenticated through username and password or SSO.
275         2. **Service Accounts:** machines that are authenticated using a service token.
276         3. **Tokens** are access keys with permissions that can be used for authentication.
277
278        See `strongdm.svc.Accounts`.
279        '''
280        self.accounts_groups = svc.AccountsGroups(channel, self)
281        '''
282         An AccountGroup links an account and a group.
283
284        See `strongdm.svc.AccountsGroups`.
285        '''
286        self.accounts_groups_history = svc.AccountsGroupsHistory(channel, self)
287        '''
288         AccountsGroupsHistory records all changes to the state of an AccountGroup.
289
290        See `strongdm.svc.AccountsGroupsHistory`.
291        '''
292        self.accounts_history = svc.AccountsHistory(channel, self)
293        '''
294         AccountsHistory records all changes to the state of an Account.
295
296        See `strongdm.svc.AccountsHistory`.
297        '''
298        self.activities = svc.Activities(channel, self)
299        '''
300         An Activity is a record of an action taken against a strongDM deployment, e.g.
301         a user creation, resource deletion, sso configuration change, etc. The Activities
302         service is read-only.
303
304        See `strongdm.svc.Activities`.
305        '''
306        self.approval_workflow_approvers = svc.ApprovalWorkflowApprovers(
307            channel, self)
308        '''
309         ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep
310
311        See `strongdm.svc.ApprovalWorkflowApprovers`.
312        '''
313        self.approval_workflow_approvers_history = svc.ApprovalWorkflowApproversHistory(
314            channel, self)
315        '''
316         ApprovalWorkflowApproversHistory records all changes to the state of an ApprovalWorkflowApprover.
317
318        See `strongdm.svc.ApprovalWorkflowApproversHistory`.
319        '''
320        self.approval_workflow_steps = svc.ApprovalWorkflowSteps(channel, self)
321        '''
322         ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow
323
324        See `strongdm.svc.ApprovalWorkflowSteps`.
325        '''
326        self.approval_workflow_steps_history = svc.ApprovalWorkflowStepsHistory(
327            channel, self)
328        '''
329         ApprovalWorkflowStepsHistory records all changes to the state of an ApprovalWorkflowStep.
330
331        See `strongdm.svc.ApprovalWorkflowStepsHistory`.
332        '''
333        self.approval_workflows = svc.ApprovalWorkflows(channel, self)
334        '''
335         ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized
336         approvers and be approved or denied.
337
338        See `strongdm.svc.ApprovalWorkflows`.
339        '''
340        self.approval_workflows_history = svc.ApprovalWorkflowsHistory(
341            channel, self)
342        '''
343         ApprovalWorkflowsHistory records all changes to the state of an ApprovalWorkflow.
344
345        See `strongdm.svc.ApprovalWorkflowsHistory`.
346        '''
347        self.control_panel = svc.ControlPanel(channel, self)
348        '''
349         ControlPanel contains all administrative controls.
350
351        See `strongdm.svc.ControlPanel`.
352        '''
353        self.discovery_connectors = svc.DiscoveryConnectors(channel, self)
354        '''
355         A Discovery Connector is a configuration object for performing Resource
356         Scans in remote systems such as AWS, GCP, Azure, and other systems.
357
358        See `strongdm.svc.DiscoveryConnectors`.
359        '''
360        self.roles = svc.Roles(channel, self)
361        '''
362         A Role has a list of access rules which determine which Resources the members
363         of the Role have access to. An Account can be a member of multiple Roles via
364         AccountAttachments.
365
366        See `strongdm.svc.Roles`.
367        '''
368        self.groups = svc.Groups(channel, self)
369        '''
370         A Group is a set of principals.
371
372        See `strongdm.svc.Groups`.
373        '''
374        self.groups_history = svc.GroupsHistory(channel, self)
375        '''
376         GroupsHistory records all changes to the state of a Group.
377
378        See `strongdm.svc.GroupsHistory`.
379        '''
380        self.groups_roles = svc.GroupsRoles(channel, self)
381        '''
382         A GroupRole is an assignment of a Group to a Role.
383
384        See `strongdm.svc.GroupsRoles`.
385        '''
386        self.groups_roles_history = svc.GroupsRolesHistory(channel, self)
387        '''
388         GroupsRolesHistory records all changes to the state of a GroupRole.
389
390        See `strongdm.svc.GroupsRolesHistory`.
391        '''
392        self.health_checks = svc.HealthChecks(channel, self)
393        '''
394         HealthChecks lists the last healthcheck between each node and resource.
395         Note the unconventional capitalization here is to prevent having a collision with GRPC
396
397        See `strongdm.svc.HealthChecks`.
398        '''
399        self.identity_aliases = svc.IdentityAliases(channel, self)
400        '''
401         IdentityAliases assign an alias to an account within an IdentitySet.
402         The alias is used as the username when connecting to a identity supported resource.
403
404        See `strongdm.svc.IdentityAliases`.
405        '''
406        self.identity_aliases_history = svc.IdentityAliasesHistory(
407            channel, self)
408        '''
409         IdentityAliasesHistory records all changes to the state of a IdentityAlias.
410
411        See `strongdm.svc.IdentityAliasesHistory`.
412        '''
413        self.identity_sets = svc.IdentitySets(channel, self)
414        '''
415         A IdentitySet is a named grouping of Identity Aliases for Accounts.
416         An Account's relationship to a IdentitySet is defined via IdentityAlias objects.
417
418        See `strongdm.svc.IdentitySets`.
419        '''
420        self.identity_sets_history = svc.IdentitySetsHistory(channel, self)
421        '''
422         IdentitySetsHistory records all changes to the state of a IdentitySet.
423
424        See `strongdm.svc.IdentitySetsHistory`.
425        '''
426        self.managed_secrets = svc.ManagedSecrets(channel, self)
427        '''
428         ManagedSecret is a private vertical for creating, reading, updating,
429         deleting, listing and rotating the managed secrets in the secrets engines as
430         an authenticated user.
431
432        See `strongdm.svc.ManagedSecrets`.
433        '''
434        self.nodes = svc.Nodes(channel, self)
435        '''
436         Nodes make up the StrongDM network, and allow your users to connect securely to your resources.
437         There are three types of nodes:
438         1. **Relay:** creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
439         2. **Gateway:** a relay that also listens for connections from StrongDM clients
440         3. **Proxy Cluster:** a cluster of workers that together mediate access from clients to resources
441
442        See `strongdm.svc.Nodes`.
443        '''
444        self.nodes_history = svc.NodesHistory(channel, self)
445        '''
446         NodesHistory records all changes to the state of a Node.
447
448        See `strongdm.svc.NodesHistory`.
449        '''
450        self.organization_history = svc.OrganizationHistory(channel, self)
451        '''
452         OrganizationHistory records all changes to the state of an Organization.
453
454        See `strongdm.svc.OrganizationHistory`.
455        '''
456        self.peering_group_nodes = svc.PeeringGroupNodes(channel, self)
457        '''
458         PeeringGroupNodes provides the building blocks necessary to obtain attach a node to a peering group.
459
460        See `strongdm.svc.PeeringGroupNodes`.
461        '''
462        self.peering_group_peers = svc.PeeringGroupPeers(channel, self)
463        '''
464         PeeringGroupPeers provides the building blocks necessary to link two peering groups.
465
466        See `strongdm.svc.PeeringGroupPeers`.
467        '''
468        self.peering_group_resources = svc.PeeringGroupResources(channel, self)
469        '''
470         PeeringGroupResources provides the building blocks necessary to obtain attach a resource to a peering group.
471
472        See `strongdm.svc.PeeringGroupResources`.
473        '''
474        self.peering_groups = svc.PeeringGroups(channel, self)
475        '''
476         PeeringGroups provides the building blocks necessary to obtain explicit network topology and routing.
477
478        See `strongdm.svc.PeeringGroups`.
479        '''
480        self.policies = svc.Policies(channel, self)
481        '''
482         Policies are the collection of one or more statements that enforce fine-grained access
483         control for the users of an organization.
484
485        See `strongdm.svc.Policies`.
486        '''
487        self.policies_history = svc.PoliciesHistory(channel, self)
488        '''
489         PoliciesHistory records all changes to the state of a Policy.
490
491        See `strongdm.svc.PoliciesHistory`.
492        '''
493        self.proxy_cluster_keys = svc.ProxyClusterKeys(channel, self)
494        '''
495         Proxy Cluster Keys are authentication keys for all proxies within a cluster.
496         The proxies within a cluster share the same key. One cluster can have
497         multiple keys in order to facilitate key rotation.
498
499        See `strongdm.svc.ProxyClusterKeys`.
500        '''
501        self.queries = svc.Queries(channel, self)
502        '''
503         A Query is a record of a single client request to a resource, such as a SQL query.
504         Long-running SSH, RDP, or Kubernetes interactive sessions also count as queries.
505         The Queries service is read-only.
506
507        See `strongdm.svc.Queries`.
508        '''
509        self.remote_identities = svc.RemoteIdentities(channel, self)
510        '''
511         RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
512
513        See `strongdm.svc.RemoteIdentities`.
514        '''
515        self.remote_identities_history = svc.RemoteIdentitiesHistory(
516            channel, self)
517        '''
518         RemoteIdentitiesHistory records all changes to the state of a RemoteIdentity.
519
520        See `strongdm.svc.RemoteIdentitiesHistory`.
521        '''
522        self.remote_identity_groups = svc.RemoteIdentityGroups(channel, self)
523        '''
524         A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
525         An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
526
527        See `strongdm.svc.RemoteIdentityGroups`.
528        '''
529        self.remote_identity_groups_history = svc.RemoteIdentityGroupsHistory(
530            channel, self)
531        '''
532         RemoteIdentityGroupsHistory records all changes to the state of a RemoteIdentityGroup.
533
534        See `strongdm.svc.RemoteIdentityGroupsHistory`.
535        '''
536        self.replays = svc.Replays(channel, self)
537        '''
538         A Replay captures the data transferred over a long-running SSH, RDP, or Kubernetes interactive session
539         (otherwise referred to as a query). The Replays service is read-only.
540
541        See `strongdm.svc.Replays`.
542        '''
543        self.resources = svc.Resources(channel, self)
544        '''
545         Resources are databases, servers, clusters, websites, or clouds that strongDM
546         delegates access to.
547
548        See `strongdm.svc.Resources`.
549        '''
550        self.resources_history = svc.ResourcesHistory(channel, self)
551        '''
552         ResourcesHistory records all changes to the state of a Resource.
553
554        See `strongdm.svc.ResourcesHistory`.
555        '''
556        self.role_resources = svc.RoleResources(channel, self)
557        '''
558         RoleResources enumerates the resources to which roles have access.
559         The RoleResources service is read-only.
560
561        See `strongdm.svc.RoleResources`.
562        '''
563        self.role_resources_history = svc.RoleResourcesHistory(channel, self)
564        '''
565         RoleResourcesHistory records all changes to the state of a RoleResource.
566
567        See `strongdm.svc.RoleResourcesHistory`.
568        '''
569        self.roles_history = svc.RolesHistory(channel, self)
570        '''
571         RolesHistory records all changes to the state of a Role.
572
573        See `strongdm.svc.RolesHistory`.
574        '''
575        self.secret_stores = svc.SecretStores(channel, self)
576        '''
577         SecretStores are servers where resource secrets (passwords, keys) are stored.
578
579        See `strongdm.svc.SecretStores`.
580        '''
581        self.secret_engines = svc.SecretEngines(channel, self)
582        '''
583
584
585        See `strongdm.svc.SecretEngines`.
586        '''
587        self.secret_store_healths = svc.SecretStoreHealths(channel, self)
588        '''
589         SecretStoreHealths exposes health states for secret stores.
590
591        See `strongdm.svc.SecretStoreHealths`.
592        '''
593        self.secret_stores_history = svc.SecretStoresHistory(channel, self)
594        '''
595         SecretStoresHistory records all changes to the state of a SecretStore.
596
597        See `strongdm.svc.SecretStoresHistory`.
598        '''
599        self.workflow_approvers = svc.WorkflowApprovers(channel, self)
600        '''
601         WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.
602
603        See `strongdm.svc.WorkflowApprovers`.
604        '''
605        self.workflow_approvers_history = svc.WorkflowApproversHistory(
606            channel, self)
607        '''
608         WorkflowApproversHistory provides records of all changes to the state of a WorkflowApprover.
609
610        See `strongdm.svc.WorkflowApproversHistory`.
611        '''
612        self.workflow_roles = svc.WorkflowRoles(channel, self)
613        '''
614         WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of
615         to request access to a resource via the workflow.
616
617        See `strongdm.svc.WorkflowRoles`.
618        '''
619        self.workflow_roles_history = svc.WorkflowRolesHistory(channel, self)
620        '''
621         WorkflowRolesHistory provides records of all changes to the state of a WorkflowRole
622
623        See `strongdm.svc.WorkflowRolesHistory`.
624        '''
625        self.workflows = svc.Workflows(channel, self)
626        '''
627         Workflows are the collection of rules that define the resources to which access can be requested,
628         the users that can request that access, and the mechanism for approving those requests which can either
629         be automatic approval or a set of users authorized to approve the requests.
630
631        See `strongdm.svc.Workflows`.
632        '''
633        self.workflows_history = svc.WorkflowsHistory(channel, self)
634        '''
635         WorkflowsHistory provides records of all changes to the state of a Workflow.
636
637        See `strongdm.svc.WorkflowsHistory`.
638        '''
639
640    def close(self):
641        '''Closes this Client and releases all resources held by it.
642
643        Closing the Client will immediately terminate all RPCs active with the
644        Client and it is not valid to invoke new RPCs with the Client.
645
646        This method is idempotent.
647        '''
648        self.channel.close()
649
650    def get_metadata(self, method_name, req):
651        return [
652            ('x-sdm-authentication', self.api_access_key),
653            ('x-sdm-signature', self.sign(method_name,
654                                          req.SerializeToString())),
655            ('x-sdm-api-version', API_VERSION),
656            ('x-sdm-user-agent', USER_AGENT),
657        ]
658
659    def sign(self, method_name, request_bytes):
660        def hmac_digest(key, msg_byte_string):
661            return hmac.new(key, msg=msg_byte_string,
662                            digestmod=hashlib.sha256).digest()
663
664        current_utc_date = datetime.datetime.now(
665            datetime.timezone.utc).strftime('%Y-%m-%d')
666        signing_key = hmac_digest(self.api_secret, current_utc_date.encode())
667        signing_key = hmac_digest(signing_key, b'sdm_api_v1')
668
669        hash = hashlib.sha256()
670
671        hash.update(method_name.encode())
672        hash.update(b'\n')
673        hash.update(request_bytes)
674
675        return base64.b64encode(hmac_digest(signing_key, hash.digest()))
676
677    def exponentialBackoff(self, retries, deadline=None):
678        def applyDeadline(delay, deadline):
679            if deadline is None:
680                return delay
681            remaining = deadline - time.time()
682            if remaining < 0:
683                return 0
684            return min(delay, remaining)
685
686        if retries == 0:
687            return applyDeadline(self.base_retry_delay, deadline)
688
689        backoff, max_delay = self.base_retry_delay, self.max_retry_delay
690        while backoff < max_delay and retries > 0:
691            backoff *= self.retry_factor
692            retries -= 1
693
694        if backoff > max_delay:
695            backoff = max_delay
696
697        # Randomize backoff delays so that if a cluster of requests start at
698        # the same time, they won't operate in lockstep.
699        backoff *= 1 + self.retry_jitter * (random.random() * 2 - 1)
700        if backoff < 0:
701            return 0
702
703        return applyDeadline(backoff, deadline)
704
705    def shouldRetry(self, retries, err, deadline=None):
706        # Check if we've passed the deadline
707        if deadline is not None and time.time() >= deadline:
708            return False
709
710        if not isinstance(err, grpc.RpcError):
711            return False
712
713        if self.retry_rate_limit_errors and err.code(
714        ) == grpc.StatusCode.RESOURCE_EXHAUSTED:
715            return True
716
717        return retries <= 3 and (err.code() == grpc.StatusCode.INTERNAL
718                                 or err.code() == grpc.StatusCode.UNAVAILABLE)
719
720    def snapshot_at(self, snapshot_datetime):
721        '''
722        Constructs a read-only client that will provide historical data from the provided timestamp.
723
724        See `SnapshotClient`.
725        '''
726        client = copy.copy(self)
727        client.snapshot_datetime = snapshot_datetime
728        client.access_requests = svc.AccessRequests(client.channel, client)
729        client.account_attachments = svc.AccountAttachments(
730            client.channel, client)
731        client.account_grants = svc.AccountGrants(client.channel, client)
732        client.account_permissions = svc.AccountPermissions(
733            client.channel, client)
734        client.account_resources = svc.AccountResources(client.channel, client)
735        client.accounts = svc.Accounts(client.channel, client)
736        client.accounts_groups = svc.AccountsGroups(client.channel, client)
737        client.approval_workflow_approvers = svc.ApprovalWorkflowApprovers(
738            client.channel, client)
739        client.approval_workflow_steps = svc.ApprovalWorkflowSteps(
740            client.channel, client)
741        client.approval_workflows = svc.ApprovalWorkflows(
742            client.channel, client)
743        client.discovery_connectors = svc.DiscoveryConnectors(
744            client.channel, client)
745        client.roles = svc.Roles(client.channel, client)
746        client.groups = svc.Groups(client.channel, client)
747        client.groups_roles = svc.GroupsRoles(client.channel, client)
748        client.identity_aliases = svc.IdentityAliases(client.channel, client)
749        client.identity_sets = svc.IdentitySets(client.channel, client)
750        client.nodes = svc.Nodes(client.channel, client)
751        client.policies = svc.Policies(client.channel, client)
752        client.proxy_cluster_keys = svc.ProxyClusterKeys(
753            client.channel, client)
754        client.remote_identities = svc.RemoteIdentities(client.channel, client)
755        client.remote_identity_groups = svc.RemoteIdentityGroups(
756            client.channel, client)
757        client.resources = svc.Resources(client.channel, client)
758        client.role_resources = svc.RoleResources(client.channel, client)
759        client.secret_stores = svc.SecretStores(client.channel, client)
760        client.workflow_approvers = svc.WorkflowApprovers(
761            client.channel, client)
762        client.workflow_roles = svc.WorkflowRoles(client.channel, client)
763        client.workflows = svc.Workflows(client.channel, client)
764        return SnapshotClient(client)

Client interacts with the strongDM API.

Client( api_access_key, api_secret, host='app.strongdm.com:443', insecure=False, retry_rate_limit_errors=True, page_limit=0)
173    def __init__(self,
174                 api_access_key,
175                 api_secret,
176                 host='app.strongdm.com:443',
177                 insecure=False,
178                 retry_rate_limit_errors=True,
179                 page_limit=0):
180        '''
181        Create a new Client.
182
183        - api_access_key: the access key to authenticate with strongDM
184        - api_secret: the secret key to authenticate with strongDM
185        '''
186        self.api_access_key = api_access_key.strip()
187        self.api_secret = base64.b64decode(api_secret.strip())
188        self.base_retry_delay = DEFAULT_BASE_RETRY_DELAY
189        self.max_retry_delay = DEFAULT_MAX_RETRY_DELAY
190        self.retry_factor = DEFAULT_RETRY_FACTOR
191        self.retry_jitter = DEFAULT_RETRY_JITTER
192        self.retry_rate_limit_errors = retry_rate_limit_errors
193        self.snapshot_datetime = None
194        self.page_limit = page_limit
195
196        try:
197            if insecure:
198                channel = grpc.insecure_channel(host)
199            else:
200                creds = grpc.ssl_channel_credentials()
201                channel = grpc.secure_channel(host, creds)
202        except Exception as e:
203            raise plumbing.convert_error_to_porcelain(e) from e
204        channel = grpc.intercept_channel(channel, _EncryptionInterceptor(self))
205        self.channel = channel
206        self.access_requests = svc.AccessRequests(channel, self)
207        '''
208         AccessRequests are requests for access to a resource that may match a Workflow.
209
210        See `strongdm.svc.AccessRequests`.
211        '''
212        self.access_request_events_history = svc.AccessRequestEventsHistory(
213            channel, self)
214        '''
215         AccessRequestEventsHistory provides records of all changes to the state of an AccessRequest.
216
217        See `strongdm.svc.AccessRequestEventsHistory`.
218        '''
219        self.access_requests_history = svc.AccessRequestsHistory(channel, self)
220        '''
221         AccessRequestsHistory provides records of all changes to the state of an AccessRequest.
222
223        See `strongdm.svc.AccessRequestsHistory`.
224        '''
225        self.account_attachments = svc.AccountAttachments(channel, self)
226        '''
227         AccountAttachments assign an account to a role.
228
229        See `strongdm.svc.AccountAttachments`.
230        '''
231        self.account_attachments_history = svc.AccountAttachmentsHistory(
232            channel, self)
233        '''
234         AccountAttachmentsHistory records all changes to the state of an AccountAttachment.
235
236        See `strongdm.svc.AccountAttachmentsHistory`.
237        '''
238        self.account_grants = svc.AccountGrants(channel, self)
239        '''
240         AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
241
242        See `strongdm.svc.AccountGrants`.
243        '''
244        self.account_grants_history = svc.AccountGrantsHistory(channel, self)
245        '''
246         AccountGrantsHistory records all changes to the state of an AccountGrant.
247
248        See `strongdm.svc.AccountGrantsHistory`.
249        '''
250        self.account_permissions = svc.AccountPermissions(channel, self)
251        '''
252         AccountPermissions records the granular permissions accounts have, allowing them to execute
253         relevant commands via StrongDM's APIs.
254
255        See `strongdm.svc.AccountPermissions`.
256        '''
257        self.account_resources = svc.AccountResources(channel, self)
258        '''
259         AccountResources enumerates the resources to which accounts have access.
260         The AccountResources service is read-only.
261
262        See `strongdm.svc.AccountResources`.
263        '''
264        self.account_resources_history = svc.AccountResourcesHistory(
265            channel, self)
266        '''
267         AccountResourcesHistory records all changes to the state of a AccountResource.
268
269        See `strongdm.svc.AccountResourcesHistory`.
270        '''
271        self.accounts = svc.Accounts(channel, self)
272        '''
273         Accounts are users that have access to strongDM. There are two types of accounts:
274         1. **Users:** humans who are authenticated through username and password or SSO.
275         2. **Service Accounts:** machines that are authenticated using a service token.
276         3. **Tokens** are access keys with permissions that can be used for authentication.
277
278        See `strongdm.svc.Accounts`.
279        '''
280        self.accounts_groups = svc.AccountsGroups(channel, self)
281        '''
282         An AccountGroup links an account and a group.
283
284        See `strongdm.svc.AccountsGroups`.
285        '''
286        self.accounts_groups_history = svc.AccountsGroupsHistory(channel, self)
287        '''
288         AccountsGroupsHistory records all changes to the state of an AccountGroup.
289
290        See `strongdm.svc.AccountsGroupsHistory`.
291        '''
292        self.accounts_history = svc.AccountsHistory(channel, self)
293        '''
294         AccountsHistory records all changes to the state of an Account.
295
296        See `strongdm.svc.AccountsHistory`.
297        '''
298        self.activities = svc.Activities(channel, self)
299        '''
300         An Activity is a record of an action taken against a strongDM deployment, e.g.
301         a user creation, resource deletion, sso configuration change, etc. The Activities
302         service is read-only.
303
304        See `strongdm.svc.Activities`.
305        '''
306        self.approval_workflow_approvers = svc.ApprovalWorkflowApprovers(
307            channel, self)
308        '''
309         ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep
310
311        See `strongdm.svc.ApprovalWorkflowApprovers`.
312        '''
313        self.approval_workflow_approvers_history = svc.ApprovalWorkflowApproversHistory(
314            channel, self)
315        '''
316         ApprovalWorkflowApproversHistory records all changes to the state of an ApprovalWorkflowApprover.
317
318        See `strongdm.svc.ApprovalWorkflowApproversHistory`.
319        '''
320        self.approval_workflow_steps = svc.ApprovalWorkflowSteps(channel, self)
321        '''
322         ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow
323
324        See `strongdm.svc.ApprovalWorkflowSteps`.
325        '''
326        self.approval_workflow_steps_history = svc.ApprovalWorkflowStepsHistory(
327            channel, self)
328        '''
329         ApprovalWorkflowStepsHistory records all changes to the state of an ApprovalWorkflowStep.
330
331        See `strongdm.svc.ApprovalWorkflowStepsHistory`.
332        '''
333        self.approval_workflows = svc.ApprovalWorkflows(channel, self)
334        '''
335         ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized
336         approvers and be approved or denied.
337
338        See `strongdm.svc.ApprovalWorkflows`.
339        '''
340        self.approval_workflows_history = svc.ApprovalWorkflowsHistory(
341            channel, self)
342        '''
343         ApprovalWorkflowsHistory records all changes to the state of an ApprovalWorkflow.
344
345        See `strongdm.svc.ApprovalWorkflowsHistory`.
346        '''
347        self.control_panel = svc.ControlPanel(channel, self)
348        '''
349         ControlPanel contains all administrative controls.
350
351        See `strongdm.svc.ControlPanel`.
352        '''
353        self.discovery_connectors = svc.DiscoveryConnectors(channel, self)
354        '''
355         A Discovery Connector is a configuration object for performing Resource
356         Scans in remote systems such as AWS, GCP, Azure, and other systems.
357
358        See `strongdm.svc.DiscoveryConnectors`.
359        '''
360        self.roles = svc.Roles(channel, self)
361        '''
362         A Role has a list of access rules which determine which Resources the members
363         of the Role have access to. An Account can be a member of multiple Roles via
364         AccountAttachments.
365
366        See `strongdm.svc.Roles`.
367        '''
368        self.groups = svc.Groups(channel, self)
369        '''
370         A Group is a set of principals.
371
372        See `strongdm.svc.Groups`.
373        '''
374        self.groups_history = svc.GroupsHistory(channel, self)
375        '''
376         GroupsHistory records all changes to the state of a Group.
377
378        See `strongdm.svc.GroupsHistory`.
379        '''
380        self.groups_roles = svc.GroupsRoles(channel, self)
381        '''
382         A GroupRole is an assignment of a Group to a Role.
383
384        See `strongdm.svc.GroupsRoles`.
385        '''
386        self.groups_roles_history = svc.GroupsRolesHistory(channel, self)
387        '''
388         GroupsRolesHistory records all changes to the state of a GroupRole.
389
390        See `strongdm.svc.GroupsRolesHistory`.
391        '''
392        self.health_checks = svc.HealthChecks(channel, self)
393        '''
394         HealthChecks lists the last healthcheck between each node and resource.
395         Note the unconventional capitalization here is to prevent having a collision with GRPC
396
397        See `strongdm.svc.HealthChecks`.
398        '''
399        self.identity_aliases = svc.IdentityAliases(channel, self)
400        '''
401         IdentityAliases assign an alias to an account within an IdentitySet.
402         The alias is used as the username when connecting to a identity supported resource.
403
404        See `strongdm.svc.IdentityAliases`.
405        '''
406        self.identity_aliases_history = svc.IdentityAliasesHistory(
407            channel, self)
408        '''
409         IdentityAliasesHistory records all changes to the state of a IdentityAlias.
410
411        See `strongdm.svc.IdentityAliasesHistory`.
412        '''
413        self.identity_sets = svc.IdentitySets(channel, self)
414        '''
415         A IdentitySet is a named grouping of Identity Aliases for Accounts.
416         An Account's relationship to a IdentitySet is defined via IdentityAlias objects.
417
418        See `strongdm.svc.IdentitySets`.
419        '''
420        self.identity_sets_history = svc.IdentitySetsHistory(channel, self)
421        '''
422         IdentitySetsHistory records all changes to the state of a IdentitySet.
423
424        See `strongdm.svc.IdentitySetsHistory`.
425        '''
426        self.managed_secrets = svc.ManagedSecrets(channel, self)
427        '''
428         ManagedSecret is a private vertical for creating, reading, updating,
429         deleting, listing and rotating the managed secrets in the secrets engines as
430         an authenticated user.
431
432        See `strongdm.svc.ManagedSecrets`.
433        '''
434        self.nodes = svc.Nodes(channel, self)
435        '''
436         Nodes make up the StrongDM network, and allow your users to connect securely to your resources.
437         There are three types of nodes:
438         1. **Relay:** creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
439         2. **Gateway:** a relay that also listens for connections from StrongDM clients
440         3. **Proxy Cluster:** a cluster of workers that together mediate access from clients to resources
441
442        See `strongdm.svc.Nodes`.
443        '''
444        self.nodes_history = svc.NodesHistory(channel, self)
445        '''
446         NodesHistory records all changes to the state of a Node.
447
448        See `strongdm.svc.NodesHistory`.
449        '''
450        self.organization_history = svc.OrganizationHistory(channel, self)
451        '''
452         OrganizationHistory records all changes to the state of an Organization.
453
454        See `strongdm.svc.OrganizationHistory`.
455        '''
456        self.peering_group_nodes = svc.PeeringGroupNodes(channel, self)
457        '''
458         PeeringGroupNodes provides the building blocks necessary to obtain attach a node to a peering group.
459
460        See `strongdm.svc.PeeringGroupNodes`.
461        '''
462        self.peering_group_peers = svc.PeeringGroupPeers(channel, self)
463        '''
464         PeeringGroupPeers provides the building blocks necessary to link two peering groups.
465
466        See `strongdm.svc.PeeringGroupPeers`.
467        '''
468        self.peering_group_resources = svc.PeeringGroupResources(channel, self)
469        '''
470         PeeringGroupResources provides the building blocks necessary to obtain attach a resource to a peering group.
471
472        See `strongdm.svc.PeeringGroupResources`.
473        '''
474        self.peering_groups = svc.PeeringGroups(channel, self)
475        '''
476         PeeringGroups provides the building blocks necessary to obtain explicit network topology and routing.
477
478        See `strongdm.svc.PeeringGroups`.
479        '''
480        self.policies = svc.Policies(channel, self)
481        '''
482         Policies are the collection of one or more statements that enforce fine-grained access
483         control for the users of an organization.
484
485        See `strongdm.svc.Policies`.
486        '''
487        self.policies_history = svc.PoliciesHistory(channel, self)
488        '''
489         PoliciesHistory records all changes to the state of a Policy.
490
491        See `strongdm.svc.PoliciesHistory`.
492        '''
493        self.proxy_cluster_keys = svc.ProxyClusterKeys(channel, self)
494        '''
495         Proxy Cluster Keys are authentication keys for all proxies within a cluster.
496         The proxies within a cluster share the same key. One cluster can have
497         multiple keys in order to facilitate key rotation.
498
499        See `strongdm.svc.ProxyClusterKeys`.
500        '''
501        self.queries = svc.Queries(channel, self)
502        '''
503         A Query is a record of a single client request to a resource, such as a SQL query.
504         Long-running SSH, RDP, or Kubernetes interactive sessions also count as queries.
505         The Queries service is read-only.
506
507        See `strongdm.svc.Queries`.
508        '''
509        self.remote_identities = svc.RemoteIdentities(channel, self)
510        '''
511         RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
512
513        See `strongdm.svc.RemoteIdentities`.
514        '''
515        self.remote_identities_history = svc.RemoteIdentitiesHistory(
516            channel, self)
517        '''
518         RemoteIdentitiesHistory records all changes to the state of a RemoteIdentity.
519
520        See `strongdm.svc.RemoteIdentitiesHistory`.
521        '''
522        self.remote_identity_groups = svc.RemoteIdentityGroups(channel, self)
523        '''
524         A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
525         An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
526
527        See `strongdm.svc.RemoteIdentityGroups`.
528        '''
529        self.remote_identity_groups_history = svc.RemoteIdentityGroupsHistory(
530            channel, self)
531        '''
532         RemoteIdentityGroupsHistory records all changes to the state of a RemoteIdentityGroup.
533
534        See `strongdm.svc.RemoteIdentityGroupsHistory`.
535        '''
536        self.replays = svc.Replays(channel, self)
537        '''
538         A Replay captures the data transferred over a long-running SSH, RDP, or Kubernetes interactive session
539         (otherwise referred to as a query). The Replays service is read-only.
540
541        See `strongdm.svc.Replays`.
542        '''
543        self.resources = svc.Resources(channel, self)
544        '''
545         Resources are databases, servers, clusters, websites, or clouds that strongDM
546         delegates access to.
547
548        See `strongdm.svc.Resources`.
549        '''
550        self.resources_history = svc.ResourcesHistory(channel, self)
551        '''
552         ResourcesHistory records all changes to the state of a Resource.
553
554        See `strongdm.svc.ResourcesHistory`.
555        '''
556        self.role_resources = svc.RoleResources(channel, self)
557        '''
558         RoleResources enumerates the resources to which roles have access.
559         The RoleResources service is read-only.
560
561        See `strongdm.svc.RoleResources`.
562        '''
563        self.role_resources_history = svc.RoleResourcesHistory(channel, self)
564        '''
565         RoleResourcesHistory records all changes to the state of a RoleResource.
566
567        See `strongdm.svc.RoleResourcesHistory`.
568        '''
569        self.roles_history = svc.RolesHistory(channel, self)
570        '''
571         RolesHistory records all changes to the state of a Role.
572
573        See `strongdm.svc.RolesHistory`.
574        '''
575        self.secret_stores = svc.SecretStores(channel, self)
576        '''
577         SecretStores are servers where resource secrets (passwords, keys) are stored.
578
579        See `strongdm.svc.SecretStores`.
580        '''
581        self.secret_engines = svc.SecretEngines(channel, self)
582        '''
583
584
585        See `strongdm.svc.SecretEngines`.
586        '''
587        self.secret_store_healths = svc.SecretStoreHealths(channel, self)
588        '''
589         SecretStoreHealths exposes health states for secret stores.
590
591        See `strongdm.svc.SecretStoreHealths`.
592        '''
593        self.secret_stores_history = svc.SecretStoresHistory(channel, self)
594        '''
595         SecretStoresHistory records all changes to the state of a SecretStore.
596
597        See `strongdm.svc.SecretStoresHistory`.
598        '''
599        self.workflow_approvers = svc.WorkflowApprovers(channel, self)
600        '''
601         WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.
602
603        See `strongdm.svc.WorkflowApprovers`.
604        '''
605        self.workflow_approvers_history = svc.WorkflowApproversHistory(
606            channel, self)
607        '''
608         WorkflowApproversHistory provides records of all changes to the state of a WorkflowApprover.
609
610        See `strongdm.svc.WorkflowApproversHistory`.
611        '''
612        self.workflow_roles = svc.WorkflowRoles(channel, self)
613        '''
614         WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of
615         to request access to a resource via the workflow.
616
617        See `strongdm.svc.WorkflowRoles`.
618        '''
619        self.workflow_roles_history = svc.WorkflowRolesHistory(channel, self)
620        '''
621         WorkflowRolesHistory provides records of all changes to the state of a WorkflowRole
622
623        See `strongdm.svc.WorkflowRolesHistory`.
624        '''
625        self.workflows = svc.Workflows(channel, self)
626        '''
627         Workflows are the collection of rules that define the resources to which access can be requested,
628         the users that can request that access, and the mechanism for approving those requests which can either
629         be automatic approval or a set of users authorized to approve the requests.
630
631        See `strongdm.svc.Workflows`.
632        '''
633        self.workflows_history = svc.WorkflowsHistory(channel, self)
634        '''
635         WorkflowsHistory provides records of all changes to the state of a Workflow.
636
637        See `strongdm.svc.WorkflowsHistory`.
638        '''

Create a new Client.

  • api_access_key: the access key to authenticate with strongDM
  • api_secret: the secret key to authenticate with strongDM
access_requests

AccessRequests are requests for access to a resource that may match a Workflow.

See strongdm.svc.AccessRequests.

access_request_events_history

AccessRequestEventsHistory provides records of all changes to the state of an AccessRequest.

See strongdm.svc.AccessRequestEventsHistory.

access_requests_history

AccessRequestsHistory provides records of all changes to the state of an AccessRequest.

See strongdm.svc.AccessRequestsHistory.

account_attachments

AccountAttachments assign an account to a role.

See strongdm.svc.AccountAttachments.

account_attachments_history

AccountAttachmentsHistory records all changes to the state of an AccountAttachment.

See strongdm.svc.AccountAttachmentsHistory.

account_grants

AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.

See strongdm.svc.AccountGrants.

account_grants_history

AccountGrantsHistory records all changes to the state of an AccountGrant.

See strongdm.svc.AccountGrantsHistory.

account_permissions

AccountPermissions records the granular permissions accounts have, allowing them to execute relevant commands via StrongDM's APIs.

See strongdm.svc.AccountPermissions.

account_resources

AccountResources enumerates the resources to which accounts have access. The AccountResources service is read-only.

See strongdm.svc.AccountResources.

account_resources_history

AccountResourcesHistory records all changes to the state of a AccountResource.

See strongdm.svc.AccountResourcesHistory.

accounts

Accounts are users that have access to strongDM. There are two types of accounts:

  1. Users: humans who are authenticated through username and password or SSO.
  2. Service Accounts: machines that are authenticated using a service token.
  3. Tokens are access keys with permissions that can be used for authentication.

See strongdm.svc.Accounts.

accounts_groups

An AccountGroup links an account and a group.

See strongdm.svc.AccountsGroups.

accounts_groups_history

AccountsGroupsHistory records all changes to the state of an AccountGroup.

See strongdm.svc.AccountsGroupsHistory.

accounts_history

AccountsHistory records all changes to the state of an Account.

See strongdm.svc.AccountsHistory.

activities

An Activity is a record of an action taken against a strongDM deployment, e.g. a user creation, resource deletion, sso configuration change, etc. The Activities service is read-only.

See strongdm.svc.Activities.

approval_workflow_approvers

ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep

See strongdm.svc.ApprovalWorkflowApprovers.

approval_workflow_approvers_history

ApprovalWorkflowApproversHistory records all changes to the state of an ApprovalWorkflowApprover.

See strongdm.svc.ApprovalWorkflowApproversHistory.

approval_workflow_steps

ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow

See strongdm.svc.ApprovalWorkflowSteps.

approval_workflow_steps_history

ApprovalWorkflowStepsHistory records all changes to the state of an ApprovalWorkflowStep.

See strongdm.svc.ApprovalWorkflowStepsHistory.

approval_workflows

ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized approvers and be approved or denied.

See strongdm.svc.ApprovalWorkflows.

approval_workflows_history

ApprovalWorkflowsHistory records all changes to the state of an ApprovalWorkflow.

See strongdm.svc.ApprovalWorkflowsHistory.

control_panel

ControlPanel contains all administrative controls.

See strongdm.svc.ControlPanel.

discovery_connectors

A Discovery Connector is a configuration object for performing Resource Scans in remote systems such as AWS, GCP, Azure, and other systems.

See strongdm.svc.DiscoveryConnectors.

roles

A Role has a list of access rules which determine which Resources the members of the Role have access to. An Account can be a member of multiple Roles via AccountAttachments.

See strongdm.svc.Roles.

groups

A Group is a set of principals.

See strongdm.svc.Groups.

groups_history

GroupsHistory records all changes to the state of a Group.

See strongdm.svc.GroupsHistory.

groups_roles

A GroupRole is an assignment of a Group to a Role.

See strongdm.svc.GroupsRoles.

groups_roles_history

GroupsRolesHistory records all changes to the state of a GroupRole.

See strongdm.svc.GroupsRolesHistory.

health_checks

HealthChecks lists the last healthcheck between each node and resource. Note the unconventional capitalization here is to prevent having a collision with GRPC

See strongdm.svc.HealthChecks.

identity_aliases

IdentityAliases assign an alias to an account within an IdentitySet. The alias is used as the username when connecting to a identity supported resource.

See strongdm.svc.IdentityAliases.

identity_aliases_history

IdentityAliasesHistory records all changes to the state of a IdentityAlias.

See strongdm.svc.IdentityAliasesHistory.

identity_sets

A IdentitySet is a named grouping of Identity Aliases for Accounts. An Account's relationship to a IdentitySet is defined via IdentityAlias objects.

See strongdm.svc.IdentitySets.

identity_sets_history

IdentitySetsHistory records all changes to the state of a IdentitySet.

See strongdm.svc.IdentitySetsHistory.

managed_secrets

ManagedSecret is a private vertical for creating, reading, updating, deleting, listing and rotating the managed secrets in the secrets engines as an authenticated user.

See strongdm.svc.ManagedSecrets.

nodes

Nodes make up the StrongDM network, and allow your users to connect securely to your resources. There are three types of nodes:

  1. Relay: creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
  2. Gateway: a relay that also listens for connections from StrongDM clients
  3. Proxy Cluster: a cluster of workers that together mediate access from clients to resources

See strongdm.svc.Nodes.

nodes_history

NodesHistory records all changes to the state of a Node.

See strongdm.svc.NodesHistory.

organization_history

OrganizationHistory records all changes to the state of an Organization.

See strongdm.svc.OrganizationHistory.

peering_group_nodes

PeeringGroupNodes provides the building blocks necessary to obtain attach a node to a peering group.

See strongdm.svc.PeeringGroupNodes.

peering_group_peers

PeeringGroupPeers provides the building blocks necessary to link two peering groups.

See strongdm.svc.PeeringGroupPeers.

peering_group_resources

PeeringGroupResources provides the building blocks necessary to obtain attach a resource to a peering group.

See strongdm.svc.PeeringGroupResources.

peering_groups

PeeringGroups provides the building blocks necessary to obtain explicit network topology and routing.

See strongdm.svc.PeeringGroups.

policies

Policies are the collection of one or more statements that enforce fine-grained access control for the users of an organization.

See strongdm.svc.Policies.

policies_history

PoliciesHistory records all changes to the state of a Policy.

See strongdm.svc.PoliciesHistory.

proxy_cluster_keys

Proxy Cluster Keys are authentication keys for all proxies within a cluster. The proxies within a cluster share the same key. One cluster can have multiple keys in order to facilitate key rotation.

See strongdm.svc.ProxyClusterKeys.

queries

A Query is a record of a single client request to a resource, such as a SQL query. Long-running SSH, RDP, or Kubernetes interactive sessions also count as queries. The Queries service is read-only.

See strongdm.svc.Queries.

remote_identities

RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.

See strongdm.svc.RemoteIdentities.

remote_identities_history

RemoteIdentitiesHistory records all changes to the state of a RemoteIdentity.

See strongdm.svc.RemoteIdentitiesHistory.

remote_identity_groups

A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts. An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.

See strongdm.svc.RemoteIdentityGroups.

remote_identity_groups_history

RemoteIdentityGroupsHistory records all changes to the state of a RemoteIdentityGroup.

See strongdm.svc.RemoteIdentityGroupsHistory.

replays

A Replay captures the data transferred over a long-running SSH, RDP, or Kubernetes interactive session (otherwise referred to as a query). The Replays service is read-only.

See strongdm.svc.Replays.

resources

Resources are databases, servers, clusters, websites, or clouds that strongDM delegates access to.

See strongdm.svc.Resources.

resources_history

ResourcesHistory records all changes to the state of a Resource.

See strongdm.svc.ResourcesHistory.

role_resources

RoleResources enumerates the resources to which roles have access. The RoleResources service is read-only.

See strongdm.svc.RoleResources.

role_resources_history

RoleResourcesHistory records all changes to the state of a RoleResource.

See strongdm.svc.RoleResourcesHistory.

roles_history

RolesHistory records all changes to the state of a Role.

See strongdm.svc.RolesHistory.

secret_stores

SecretStores are servers where resource secrets (passwords, keys) are stored.

See strongdm.svc.SecretStores.

secret_engines
secret_store_healths

SecretStoreHealths exposes health states for secret stores.

See strongdm.svc.SecretStoreHealths.

secret_stores_history

SecretStoresHistory records all changes to the state of a SecretStore.

See strongdm.svc.SecretStoresHistory.

workflow_approvers

WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.

See strongdm.svc.WorkflowApprovers.

workflow_approvers_history

WorkflowApproversHistory provides records of all changes to the state of a WorkflowApprover.

See strongdm.svc.WorkflowApproversHistory.

workflow_roles

WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of to request access to a resource via the workflow.

See strongdm.svc.WorkflowRoles.

workflow_roles_history

WorkflowRolesHistory provides records of all changes to the state of a WorkflowRole

See strongdm.svc.WorkflowRolesHistory.

workflows

Workflows are the collection of rules that define the resources to which access can be requested, the users that can request that access, and the mechanism for approving those requests which can either be automatic approval or a set of users authorized to approve the requests.

See strongdm.svc.Workflows.

workflows_history

WorkflowsHistory provides records of all changes to the state of a Workflow.

See strongdm.svc.WorkflowsHistory.

def close(self)
640    def close(self):
641        '''Closes this Client and releases all resources held by it.
642
643        Closing the Client will immediately terminate all RPCs active with the
644        Client and it is not valid to invoke new RPCs with the Client.
645
646        This method is idempotent.
647        '''
648        self.channel.close()

Closes this Client and releases all resources held by it.

Closing the Client will immediately terminate all RPCs active with the Client and it is not valid to invoke new RPCs with the Client.

This method is idempotent.

def get_metadata(self, method_name, req)
650    def get_metadata(self, method_name, req):
651        return [
652            ('x-sdm-authentication', self.api_access_key),
653            ('x-sdm-signature', self.sign(method_name,
654                                          req.SerializeToString())),
655            ('x-sdm-api-version', API_VERSION),
656            ('x-sdm-user-agent', USER_AGENT),
657        ]
def sign(self, method_name, request_bytes)
659    def sign(self, method_name, request_bytes):
660        def hmac_digest(key, msg_byte_string):
661            return hmac.new(key, msg=msg_byte_string,
662                            digestmod=hashlib.sha256).digest()
663
664        current_utc_date = datetime.datetime.now(
665            datetime.timezone.utc).strftime('%Y-%m-%d')
666        signing_key = hmac_digest(self.api_secret, current_utc_date.encode())
667        signing_key = hmac_digest(signing_key, b'sdm_api_v1')
668
669        hash = hashlib.sha256()
670
671        hash.update(method_name.encode())
672        hash.update(b'\n')
673        hash.update(request_bytes)
674
675        return base64.b64encode(hmac_digest(signing_key, hash.digest()))
def exponentialBackoff(self, retries, deadline=None)
677    def exponentialBackoff(self, retries, deadline=None):
678        def applyDeadline(delay, deadline):
679            if deadline is None:
680                return delay
681            remaining = deadline - time.time()
682            if remaining < 0:
683                return 0
684            return min(delay, remaining)
685
686        if retries == 0:
687            return applyDeadline(self.base_retry_delay, deadline)
688
689        backoff, max_delay = self.base_retry_delay, self.max_retry_delay
690        while backoff < max_delay and retries > 0:
691            backoff *= self.retry_factor
692            retries -= 1
693
694        if backoff > max_delay:
695            backoff = max_delay
696
697        # Randomize backoff delays so that if a cluster of requests start at
698        # the same time, they won't operate in lockstep.
699        backoff *= 1 + self.retry_jitter * (random.random() * 2 - 1)
700        if backoff < 0:
701            return 0
702
703        return applyDeadline(backoff, deadline)
def shouldRetry(self, retries, err, deadline=None)
705    def shouldRetry(self, retries, err, deadline=None):
706        # Check if we've passed the deadline
707        if deadline is not None and time.time() >= deadline:
708            return False
709
710        if not isinstance(err, grpc.RpcError):
711            return False
712
713        if self.retry_rate_limit_errors and err.code(
714        ) == grpc.StatusCode.RESOURCE_EXHAUSTED:
715            return True
716
717        return retries <= 3 and (err.code() == grpc.StatusCode.INTERNAL
718                                 or err.code() == grpc.StatusCode.UNAVAILABLE)
def snapshot_at(self, snapshot_datetime)
720    def snapshot_at(self, snapshot_datetime):
721        '''
722        Constructs a read-only client that will provide historical data from the provided timestamp.
723
724        See `SnapshotClient`.
725        '''
726        client = copy.copy(self)
727        client.snapshot_datetime = snapshot_datetime
728        client.access_requests = svc.AccessRequests(client.channel, client)
729        client.account_attachments = svc.AccountAttachments(
730            client.channel, client)
731        client.account_grants = svc.AccountGrants(client.channel, client)
732        client.account_permissions = svc.AccountPermissions(
733            client.channel, client)
734        client.account_resources = svc.AccountResources(client.channel, client)
735        client.accounts = svc.Accounts(client.channel, client)
736        client.accounts_groups = svc.AccountsGroups(client.channel, client)
737        client.approval_workflow_approvers = svc.ApprovalWorkflowApprovers(
738            client.channel, client)
739        client.approval_workflow_steps = svc.ApprovalWorkflowSteps(
740            client.channel, client)
741        client.approval_workflows = svc.ApprovalWorkflows(
742            client.channel, client)
743        client.discovery_connectors = svc.DiscoveryConnectors(
744            client.channel, client)
745        client.roles = svc.Roles(client.channel, client)
746        client.groups = svc.Groups(client.channel, client)
747        client.groups_roles = svc.GroupsRoles(client.channel, client)
748        client.identity_aliases = svc.IdentityAliases(client.channel, client)
749        client.identity_sets = svc.IdentitySets(client.channel, client)
750        client.nodes = svc.Nodes(client.channel, client)
751        client.policies = svc.Policies(client.channel, client)
752        client.proxy_cluster_keys = svc.ProxyClusterKeys(
753            client.channel, client)
754        client.remote_identities = svc.RemoteIdentities(client.channel, client)
755        client.remote_identity_groups = svc.RemoteIdentityGroups(
756            client.channel, client)
757        client.resources = svc.Resources(client.channel, client)
758        client.role_resources = svc.RoleResources(client.channel, client)
759        client.secret_stores = svc.SecretStores(client.channel, client)
760        client.workflow_approvers = svc.WorkflowApprovers(
761            client.channel, client)
762        client.workflow_roles = svc.WorkflowRoles(client.channel, client)
763        client.workflows = svc.Workflows(client.channel, client)
764        return SnapshotClient(client)

Constructs a read-only client that will provide historical data from the provided timestamp.

See SnapshotClient.

class SnapshotClient:
767class SnapshotClient:
768    '''SnapshotClient exposes methods to query historical records at a provided timestamp.'''
769    def __init__(self, client):
770        self.access_requests = svc.SnapshotAccessRequests(
771            client.access_requests)
772        '''
773         AccessRequests are requests for access to a resource that may match a Workflow.
774
775        See `strongdm.svc.SnapshotAccessRequests`.
776        '''
777        self.account_attachments = svc.SnapshotAccountAttachments(
778            client.account_attachments)
779        '''
780         AccountAttachments assign an account to a role.
781
782        See `strongdm.svc.SnapshotAccountAttachments`.
783        '''
784        self.account_grants = svc.SnapshotAccountGrants(client.account_grants)
785        '''
786         AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
787
788        See `strongdm.svc.SnapshotAccountGrants`.
789        '''
790        self.account_permissions = svc.SnapshotAccountPermissions(
791            client.account_permissions)
792        '''
793         AccountPermissions records the granular permissions accounts have, allowing them to execute
794         relevant commands via StrongDM's APIs.
795
796        See `strongdm.svc.SnapshotAccountPermissions`.
797        '''
798        self.account_resources = svc.SnapshotAccountResources(
799            client.account_resources)
800        '''
801         AccountResources enumerates the resources to which accounts have access.
802         The AccountResources service is read-only.
803
804        See `strongdm.svc.SnapshotAccountResources`.
805        '''
806        self.accounts = svc.SnapshotAccounts(client.accounts)
807        '''
808         Accounts are users that have access to strongDM. There are two types of accounts:
809         1. **Users:** humans who are authenticated through username and password or SSO.
810         2. **Service Accounts:** machines that are authenticated using a service token.
811         3. **Tokens** are access keys with permissions that can be used for authentication.
812
813        See `strongdm.svc.SnapshotAccounts`.
814        '''
815        self.accounts_groups = svc.SnapshotAccountsGroups(
816            client.accounts_groups)
817        '''
818         An AccountGroup links an account and a group.
819
820        See `strongdm.svc.SnapshotAccountsGroups`.
821        '''
822        self.approval_workflow_approvers = svc.SnapshotApprovalWorkflowApprovers(
823            client.approval_workflow_approvers)
824        '''
825         ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep
826
827        See `strongdm.svc.SnapshotApprovalWorkflowApprovers`.
828        '''
829        self.approval_workflow_steps = svc.SnapshotApprovalWorkflowSteps(
830            client.approval_workflow_steps)
831        '''
832         ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow
833
834        See `strongdm.svc.SnapshotApprovalWorkflowSteps`.
835        '''
836        self.approval_workflows = svc.SnapshotApprovalWorkflows(
837            client.approval_workflows)
838        '''
839         ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized
840         approvers and be approved or denied.
841
842        See `strongdm.svc.SnapshotApprovalWorkflows`.
843        '''
844        self.discovery_connectors = svc.SnapshotDiscoveryConnectors(
845            client.discovery_connectors)
846        '''
847         A Discovery Connector is a configuration object for performing Resource
848         Scans in remote systems such as AWS, GCP, Azure, and other systems.
849
850        See `strongdm.svc.SnapshotDiscoveryConnectors`.
851        '''
852        self.roles = svc.SnapshotRoles(client.roles)
853        '''
854         A Role has a list of access rules which determine which Resources the members
855         of the Role have access to. An Account can be a member of multiple Roles via
856         AccountAttachments.
857
858        See `strongdm.svc.SnapshotRoles`.
859        '''
860        self.groups = svc.SnapshotGroups(client.groups)
861        '''
862         A Group is a set of principals.
863
864        See `strongdm.svc.SnapshotGroups`.
865        '''
866        self.groups_roles = svc.SnapshotGroupsRoles(client.groups_roles)
867        '''
868         A GroupRole is an assignment of a Group to a Role.
869
870        See `strongdm.svc.SnapshotGroupsRoles`.
871        '''
872        self.identity_aliases = svc.SnapshotIdentityAliases(
873            client.identity_aliases)
874        '''
875         IdentityAliases assign an alias to an account within an IdentitySet.
876         The alias is used as the username when connecting to a identity supported resource.
877
878        See `strongdm.svc.SnapshotIdentityAliases`.
879        '''
880        self.identity_sets = svc.SnapshotIdentitySets(client.identity_sets)
881        '''
882         A IdentitySet is a named grouping of Identity Aliases for Accounts.
883         An Account's relationship to a IdentitySet is defined via IdentityAlias objects.
884
885        See `strongdm.svc.SnapshotIdentitySets`.
886        '''
887        self.nodes = svc.SnapshotNodes(client.nodes)
888        '''
889         Nodes make up the StrongDM network, and allow your users to connect securely to your resources.
890         There are three types of nodes:
891         1. **Relay:** creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
892         2. **Gateway:** a relay that also listens for connections from StrongDM clients
893         3. **Proxy Cluster:** a cluster of workers that together mediate access from clients to resources
894
895        See `strongdm.svc.SnapshotNodes`.
896        '''
897        self.policies = svc.SnapshotPolicies(client.policies)
898        '''
899         Policies are the collection of one or more statements that enforce fine-grained access
900         control for the users of an organization.
901
902        See `strongdm.svc.SnapshotPolicies`.
903        '''
904        self.proxy_cluster_keys = svc.SnapshotProxyClusterKeys(
905            client.proxy_cluster_keys)
906        '''
907         Proxy Cluster Keys are authentication keys for all proxies within a cluster.
908         The proxies within a cluster share the same key. One cluster can have
909         multiple keys in order to facilitate key rotation.
910
911        See `strongdm.svc.SnapshotProxyClusterKeys`.
912        '''
913        self.remote_identities = svc.SnapshotRemoteIdentities(
914            client.remote_identities)
915        '''
916         RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
917
918        See `strongdm.svc.SnapshotRemoteIdentities`.
919        '''
920        self.remote_identity_groups = svc.SnapshotRemoteIdentityGroups(
921            client.remote_identity_groups)
922        '''
923         A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
924         An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
925
926        See `strongdm.svc.SnapshotRemoteIdentityGroups`.
927        '''
928        self.resources = svc.SnapshotResources(client.resources)
929        '''
930         Resources are databases, servers, clusters, websites, or clouds that strongDM
931         delegates access to.
932
933        See `strongdm.svc.SnapshotResources`.
934        '''
935        self.role_resources = svc.SnapshotRoleResources(client.role_resources)
936        '''
937         RoleResources enumerates the resources to which roles have access.
938         The RoleResources service is read-only.
939
940        See `strongdm.svc.SnapshotRoleResources`.
941        '''
942        self.secret_stores = svc.SnapshotSecretStores(client.secret_stores)
943        '''
944         SecretStores are servers where resource secrets (passwords, keys) are stored.
945
946        See `strongdm.svc.SnapshotSecretStores`.
947        '''
948        self.workflow_approvers = svc.SnapshotWorkflowApprovers(
949            client.workflow_approvers)
950        '''
951         WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.
952
953        See `strongdm.svc.SnapshotWorkflowApprovers`.
954        '''
955        self.workflow_roles = svc.SnapshotWorkflowRoles(client.workflow_roles)
956        '''
957         WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of
958         to request access to a resource via the workflow.
959
960        See `strongdm.svc.SnapshotWorkflowRoles`.
961        '''
962        self.workflows = svc.SnapshotWorkflows(client.workflows)
963        '''
964         Workflows are the collection of rules that define the resources to which access can be requested,
965         the users that can request that access, and the mechanism for approving those requests which can either
966         be automatic approval or a set of users authorized to approve the requests.
967
968        See `strongdm.svc.SnapshotWorkflows`.
969        '''

SnapshotClient exposes methods to query historical records at a provided timestamp.

SnapshotClient(client)
769    def __init__(self, client):
770        self.access_requests = svc.SnapshotAccessRequests(
771            client.access_requests)
772        '''
773         AccessRequests are requests for access to a resource that may match a Workflow.
774
775        See `strongdm.svc.SnapshotAccessRequests`.
776        '''
777        self.account_attachments = svc.SnapshotAccountAttachments(
778            client.account_attachments)
779        '''
780         AccountAttachments assign an account to a role.
781
782        See `strongdm.svc.SnapshotAccountAttachments`.
783        '''
784        self.account_grants = svc.SnapshotAccountGrants(client.account_grants)
785        '''
786         AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
787
788        See `strongdm.svc.SnapshotAccountGrants`.
789        '''
790        self.account_permissions = svc.SnapshotAccountPermissions(
791            client.account_permissions)
792        '''
793         AccountPermissions records the granular permissions accounts have, allowing them to execute
794         relevant commands via StrongDM's APIs.
795
796        See `strongdm.svc.SnapshotAccountPermissions`.
797        '''
798        self.account_resources = svc.SnapshotAccountResources(
799            client.account_resources)
800        '''
801         AccountResources enumerates the resources to which accounts have access.
802         The AccountResources service is read-only.
803
804        See `strongdm.svc.SnapshotAccountResources`.
805        '''
806        self.accounts = svc.SnapshotAccounts(client.accounts)
807        '''
808         Accounts are users that have access to strongDM. There are two types of accounts:
809         1. **Users:** humans who are authenticated through username and password or SSO.
810         2. **Service Accounts:** machines that are authenticated using a service token.
811         3. **Tokens** are access keys with permissions that can be used for authentication.
812
813        See `strongdm.svc.SnapshotAccounts`.
814        '''
815        self.accounts_groups = svc.SnapshotAccountsGroups(
816            client.accounts_groups)
817        '''
818         An AccountGroup links an account and a group.
819
820        See `strongdm.svc.SnapshotAccountsGroups`.
821        '''
822        self.approval_workflow_approvers = svc.SnapshotApprovalWorkflowApprovers(
823            client.approval_workflow_approvers)
824        '''
825         ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep
826
827        See `strongdm.svc.SnapshotApprovalWorkflowApprovers`.
828        '''
829        self.approval_workflow_steps = svc.SnapshotApprovalWorkflowSteps(
830            client.approval_workflow_steps)
831        '''
832         ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow
833
834        See `strongdm.svc.SnapshotApprovalWorkflowSteps`.
835        '''
836        self.approval_workflows = svc.SnapshotApprovalWorkflows(
837            client.approval_workflows)
838        '''
839         ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized
840         approvers and be approved or denied.
841
842        See `strongdm.svc.SnapshotApprovalWorkflows`.
843        '''
844        self.discovery_connectors = svc.SnapshotDiscoveryConnectors(
845            client.discovery_connectors)
846        '''
847         A Discovery Connector is a configuration object for performing Resource
848         Scans in remote systems such as AWS, GCP, Azure, and other systems.
849
850        See `strongdm.svc.SnapshotDiscoveryConnectors`.
851        '''
852        self.roles = svc.SnapshotRoles(client.roles)
853        '''
854         A Role has a list of access rules which determine which Resources the members
855         of the Role have access to. An Account can be a member of multiple Roles via
856         AccountAttachments.
857
858        See `strongdm.svc.SnapshotRoles`.
859        '''
860        self.groups = svc.SnapshotGroups(client.groups)
861        '''
862         A Group is a set of principals.
863
864        See `strongdm.svc.SnapshotGroups`.
865        '''
866        self.groups_roles = svc.SnapshotGroupsRoles(client.groups_roles)
867        '''
868         A GroupRole is an assignment of a Group to a Role.
869
870        See `strongdm.svc.SnapshotGroupsRoles`.
871        '''
872        self.identity_aliases = svc.SnapshotIdentityAliases(
873            client.identity_aliases)
874        '''
875         IdentityAliases assign an alias to an account within an IdentitySet.
876         The alias is used as the username when connecting to a identity supported resource.
877
878        See `strongdm.svc.SnapshotIdentityAliases`.
879        '''
880        self.identity_sets = svc.SnapshotIdentitySets(client.identity_sets)
881        '''
882         A IdentitySet is a named grouping of Identity Aliases for Accounts.
883         An Account's relationship to a IdentitySet is defined via IdentityAlias objects.
884
885        See `strongdm.svc.SnapshotIdentitySets`.
886        '''
887        self.nodes = svc.SnapshotNodes(client.nodes)
888        '''
889         Nodes make up the StrongDM network, and allow your users to connect securely to your resources.
890         There are three types of nodes:
891         1. **Relay:** creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
892         2. **Gateway:** a relay that also listens for connections from StrongDM clients
893         3. **Proxy Cluster:** a cluster of workers that together mediate access from clients to resources
894
895        See `strongdm.svc.SnapshotNodes`.
896        '''
897        self.policies = svc.SnapshotPolicies(client.policies)
898        '''
899         Policies are the collection of one or more statements that enforce fine-grained access
900         control for the users of an organization.
901
902        See `strongdm.svc.SnapshotPolicies`.
903        '''
904        self.proxy_cluster_keys = svc.SnapshotProxyClusterKeys(
905            client.proxy_cluster_keys)
906        '''
907         Proxy Cluster Keys are authentication keys for all proxies within a cluster.
908         The proxies within a cluster share the same key. One cluster can have
909         multiple keys in order to facilitate key rotation.
910
911        See `strongdm.svc.SnapshotProxyClusterKeys`.
912        '''
913        self.remote_identities = svc.SnapshotRemoteIdentities(
914            client.remote_identities)
915        '''
916         RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
917
918        See `strongdm.svc.SnapshotRemoteIdentities`.
919        '''
920        self.remote_identity_groups = svc.SnapshotRemoteIdentityGroups(
921            client.remote_identity_groups)
922        '''
923         A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
924         An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
925
926        See `strongdm.svc.SnapshotRemoteIdentityGroups`.
927        '''
928        self.resources = svc.SnapshotResources(client.resources)
929        '''
930         Resources are databases, servers, clusters, websites, or clouds that strongDM
931         delegates access to.
932
933        See `strongdm.svc.SnapshotResources`.
934        '''
935        self.role_resources = svc.SnapshotRoleResources(client.role_resources)
936        '''
937         RoleResources enumerates the resources to which roles have access.
938         The RoleResources service is read-only.
939
940        See `strongdm.svc.SnapshotRoleResources`.
941        '''
942        self.secret_stores = svc.SnapshotSecretStores(client.secret_stores)
943        '''
944         SecretStores are servers where resource secrets (passwords, keys) are stored.
945
946        See `strongdm.svc.SnapshotSecretStores`.
947        '''
948        self.workflow_approvers = svc.SnapshotWorkflowApprovers(
949            client.workflow_approvers)
950        '''
951         WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.
952
953        See `strongdm.svc.SnapshotWorkflowApprovers`.
954        '''
955        self.workflow_roles = svc.SnapshotWorkflowRoles(client.workflow_roles)
956        '''
957         WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of
958         to request access to a resource via the workflow.
959
960        See `strongdm.svc.SnapshotWorkflowRoles`.
961        '''
962        self.workflows = svc.SnapshotWorkflows(client.workflows)
963        '''
964         Workflows are the collection of rules that define the resources to which access can be requested,
965         the users that can request that access, and the mechanism for approving those requests which can either
966         be automatic approval or a set of users authorized to approve the requests.
967
968        See `strongdm.svc.SnapshotWorkflows`.
969        '''
access_requests

AccessRequests are requests for access to a resource that may match a Workflow.

See strongdm.svc.SnapshotAccessRequests.

account_attachments

AccountAttachments assign an account to a role.

See strongdm.svc.SnapshotAccountAttachments.

account_grants

AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.

See strongdm.svc.SnapshotAccountGrants.

account_permissions

AccountPermissions records the granular permissions accounts have, allowing them to execute relevant commands via StrongDM's APIs.

See strongdm.svc.SnapshotAccountPermissions.

account_resources

AccountResources enumerates the resources to which accounts have access. The AccountResources service is read-only.

See strongdm.svc.SnapshotAccountResources.

accounts

Accounts are users that have access to strongDM. There are two types of accounts:

  1. Users: humans who are authenticated through username and password or SSO.
  2. Service Accounts: machines that are authenticated using a service token.
  3. Tokens are access keys with permissions that can be used for authentication.

See strongdm.svc.SnapshotAccounts.

accounts_groups

An AccountGroup links an account and a group.

See strongdm.svc.SnapshotAccountsGroups.

approval_workflow_approvers

ApprovalWorkflowApprovers link approval workflow approvers to an ApprovalWorkflowStep

See strongdm.svc.SnapshotApprovalWorkflowApprovers.

approval_workflow_steps

ApprovalWorkflowSteps link approval workflow steps to an ApprovalWorkflow

See strongdm.svc.SnapshotApprovalWorkflowSteps.

approval_workflows

ApprovalWorkflows are the mechanism by which requests for access can be viewed by authorized approvers and be approved or denied.

See strongdm.svc.SnapshotApprovalWorkflows.

discovery_connectors

A Discovery Connector is a configuration object for performing Resource Scans in remote systems such as AWS, GCP, Azure, and other systems.

See strongdm.svc.SnapshotDiscoveryConnectors.

roles

A Role has a list of access rules which determine which Resources the members of the Role have access to. An Account can be a member of multiple Roles via AccountAttachments.

See strongdm.svc.SnapshotRoles.

groups

A Group is a set of principals.

See strongdm.svc.SnapshotGroups.

groups_roles

A GroupRole is an assignment of a Group to a Role.

See strongdm.svc.SnapshotGroupsRoles.

identity_aliases

IdentityAliases assign an alias to an account within an IdentitySet. The alias is used as the username when connecting to a identity supported resource.

See strongdm.svc.SnapshotIdentityAliases.

identity_sets

A IdentitySet is a named grouping of Identity Aliases for Accounts. An Account's relationship to a IdentitySet is defined via IdentityAlias objects.

See strongdm.svc.SnapshotIdentitySets.

nodes

Nodes make up the StrongDM network, and allow your users to connect securely to your resources. There are three types of nodes:

  1. Relay: creates connectivity to your datasources, while maintaining the egress-only nature of your firewall
  2. Gateway: a relay that also listens for connections from StrongDM clients
  3. Proxy Cluster: a cluster of workers that together mediate access from clients to resources

See strongdm.svc.SnapshotNodes.

policies

Policies are the collection of one or more statements that enforce fine-grained access control for the users of an organization.

See strongdm.svc.SnapshotPolicies.

proxy_cluster_keys

Proxy Cluster Keys are authentication keys for all proxies within a cluster. The proxies within a cluster share the same key. One cluster can have multiple keys in order to facilitate key rotation.

See strongdm.svc.SnapshotProxyClusterKeys.

remote_identities

RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.

See strongdm.svc.SnapshotRemoteIdentities.

remote_identity_groups

A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts. An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.

See strongdm.svc.SnapshotRemoteIdentityGroups.

resources

Resources are databases, servers, clusters, websites, or clouds that strongDM delegates access to.

See strongdm.svc.SnapshotResources.

role_resources

RoleResources enumerates the resources to which roles have access. The RoleResources service is read-only.

See strongdm.svc.SnapshotRoleResources.

secret_stores

SecretStores are servers where resource secrets (passwords, keys) are stored.

See strongdm.svc.SnapshotSecretStores.

workflow_approvers

WorkflowApprovers is an account or a role with the ability to approve requests bound to a workflow.

See strongdm.svc.SnapshotWorkflowApprovers.

workflow_roles

WorkflowRole links a role to a workflow. The linked roles indicate which roles a user must be a part of to request access to a resource via the workflow.

See strongdm.svc.SnapshotWorkflowRoles.

workflows

Workflows are the collection of rules that define the resources to which access can be requested, the users that can request that access, and the mechanism for approving those requests which can either be automatic approval or a set of users authorized to approve the requests.

See strongdm.svc.SnapshotWorkflows.