strongdm 3.6.1__zip → 3.7.0__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. {strongdm-3.6.1 → strongdm-3.7.0}/PKG-INFO +2 -2
  2. {strongdm-3.6.1 → strongdm-3.7.0}/setup.py +2 -2
  3. strongdm-3.7.0/strongdm/account_attachments_history_pb2.py +96 -0
  4. strongdm-3.7.0/strongdm/account_attachments_history_pb2_grpc.py +84 -0
  5. strongdm-3.7.0/strongdm/account_grants_history_pb2.py +96 -0
  6. strongdm-3.7.0/strongdm/account_grants_history_pb2_grpc.py +84 -0
  7. strongdm-3.7.0/strongdm/account_permissions_pb2.py +97 -0
  8. strongdm-3.7.0/strongdm/account_permissions_pb2_grpc.py +87 -0
  9. strongdm-3.7.0/strongdm/account_resources_pb2.py +99 -0
  10. strongdm-3.7.0/strongdm/account_resources_pb2_grpc.py +87 -0
  11. strongdm-3.7.0/strongdm/accounts_history_pb2.py +96 -0
  12. strongdm-3.7.0/strongdm/accounts_history_pb2_grpc.py +84 -0
  13. strongdm-3.7.0/strongdm/activities_pb2.py +177 -0
  14. strongdm-3.7.0/strongdm/activities_pb2_grpc.py +124 -0
  15. strongdm-3.7.0/strongdm/client.py +432 -0
  16. strongdm-3.7.0/strongdm/constants.py +377 -0
  17. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/drivers_pb2.py +6 -6
  18. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/models.py +1872 -132
  19. strongdm-3.7.0/strongdm/nodes_history_pb2.py +96 -0
  20. strongdm-3.7.0/strongdm/nodes_history_pb2_grpc.py +84 -0
  21. strongdm-3.7.0/strongdm/organization_history_pb2.py +154 -0
  22. strongdm-3.7.0/strongdm/organization_history_pb2_grpc.py +84 -0
  23. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/plumbing.py +935 -0
  24. strongdm-3.7.0/strongdm/queries_pb2.py +133 -0
  25. strongdm-3.7.0/strongdm/queries_pb2_grpc.py +90 -0
  26. strongdm-3.7.0/strongdm/remote_identities_history_pb2.py +96 -0
  27. strongdm-3.7.0/strongdm/remote_identities_history_pb2_grpc.py +84 -0
  28. strongdm-3.7.0/strongdm/remote_identity_groups_history_pb2.py +96 -0
  29. strongdm-3.7.0/strongdm/remote_identity_groups_history_pb2_grpc.py +84 -0
  30. strongdm-3.7.0/strongdm/replays_pb2.py +107 -0
  31. strongdm-3.7.0/strongdm/replays_pb2_grpc.py +87 -0
  32. strongdm-3.7.0/strongdm/resources_history_pb2.py +96 -0
  33. strongdm-3.7.0/strongdm/resources_history_pb2_grpc.py +84 -0
  34. strongdm-3.7.0/strongdm/role_resources_history_pb2.py +96 -0
  35. strongdm-3.7.0/strongdm/role_resources_history_pb2_grpc.py +84 -0
  36. strongdm-3.7.0/strongdm/role_resources_pb2.py +93 -0
  37. strongdm-3.7.0/strongdm/role_resources_pb2_grpc.py +87 -0
  38. strongdm-3.7.0/strongdm/roles_history_pb2.py +96 -0
  39. strongdm-3.7.0/strongdm/roles_history_pb2_grpc.py +84 -0
  40. strongdm-3.7.0/strongdm/secret_stores_history_pb2.py +96 -0
  41. strongdm-3.7.0/strongdm/secret_stores_history_pb2_grpc.py +84 -0
  42. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/svc.py +1199 -12
  43. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm.egg-info/PKG-INFO +2 -2
  44. strongdm-3.7.0/strongdm.egg-info/SOURCES.txt +78 -0
  45. strongdm-3.6.1/strongdm/client.py +0 -199
  46. strongdm-3.6.1/strongdm/constants.py +0 -66
  47. strongdm-3.6.1/strongdm.egg-info/SOURCES.txt +0 -44
  48. {strongdm-3.6.1 → strongdm-3.7.0}/README.md +0 -0
  49. {strongdm-3.6.1 → strongdm-3.7.0}/setup.cfg +0 -0
  50. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/__init__.py +0 -0
  51. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/account_attachments_pb2.py +0 -0
  52. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/account_attachments_pb2_grpc.py +0 -0
  53. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/account_grants_pb2.py +0 -0
  54. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/account_grants_pb2_grpc.py +0 -0
  55. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/accounts_pb2.py +0 -0
  56. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/accounts_pb2_grpc.py +0 -0
  57. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/control_panel_pb2.py +0 -0
  58. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/control_panel_pb2_grpc.py +0 -0
  59. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/drivers_pb2_grpc.py +0 -0
  60. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/errors.py +0 -0
  61. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/nodes_pb2.py +0 -0
  62. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/nodes_pb2_grpc.py +0 -0
  63. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/options_pb2.py +0 -0
  64. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/options_pb2_grpc.py +0 -0
  65. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/remote_identities_pb2.py +0 -0
  66. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/remote_identities_pb2_grpc.py +0 -0
  67. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/remote_identity_groups_pb2.py +0 -0
  68. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/remote_identity_groups_pb2_grpc.py +0 -0
  69. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/resources_pb2.py +0 -0
  70. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/resources_pb2_grpc.py +0 -0
  71. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/roles_pb2.py +0 -0
  72. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/roles_pb2_grpc.py +0 -0
  73. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/secret_store_types_pb2.py +0 -0
  74. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/secret_store_types_pb2_grpc.py +0 -0
  75. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/secret_stores_pb2.py +0 -0
  76. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/secret_stores_pb2_grpc.py +0 -0
  77. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/spec_pb2.py +0 -0
  78. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/spec_pb2_grpc.py +0 -0
  79. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/tags_pb2.py +0 -0
  80. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm/tags_pb2_grpc.py +0 -0
  81. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm.egg-info/dependency_links.txt +0 -0
  82. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm.egg-info/requires.txt +0 -0
  83. {strongdm-3.6.1 → strongdm-3.7.0}/strongdm.egg-info/top_level.txt +0 -0
@@ -0,0 +1,124 @@
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
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
16
+ """Client and server classes corresponding to protobuf-defined services."""
17
+ import grpc
18
+
19
+ from . import activities_pb2 as activities__pb2
20
+
21
+
22
+ class ActivitiesStub(object):
23
+ """An Activity is a record of an action taken against a strongDM deployment, e.g.
24
+ a user creation, resource deletion, sso configuration change, etc. The Activities
25
+ service is read-only.
26
+ """
27
+
28
+ def __init__(self, channel):
29
+ """Constructor.
30
+
31
+ Args:
32
+ channel: A grpc.Channel.
33
+ """
34
+ self.Get = channel.unary_unary(
35
+ '/v1.Activities/Get',
36
+ request_serializer=activities__pb2.ActivityGetRequest.SerializeToString,
37
+ response_deserializer=activities__pb2.ActivityGetResponse.FromString,
38
+ )
39
+ self.List = channel.unary_unary(
40
+ '/v1.Activities/List',
41
+ request_serializer=activities__pb2.ActivityListRequest.SerializeToString,
42
+ response_deserializer=activities__pb2.ActivityListResponse.FromString,
43
+ )
44
+
45
+
46
+ class ActivitiesServicer(object):
47
+ """An Activity is a record of an action taken against a strongDM deployment, e.g.
48
+ a user creation, resource deletion, sso configuration change, etc. The Activities
49
+ service is read-only.
50
+ """
51
+
52
+ def Get(self, request, context):
53
+ """Get reads one Activity by ID.
54
+ """
55
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
56
+ context.set_details('Method not implemented!')
57
+ raise NotImplementedError('Method not implemented!')
58
+
59
+ def List(self, request, context):
60
+ """List gets a list of Activities matching a given set of criteria.
61
+ """
62
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
63
+ context.set_details('Method not implemented!')
64
+ raise NotImplementedError('Method not implemented!')
65
+
66
+
67
+ def add_ActivitiesServicer_to_server(servicer, server):
68
+ rpc_method_handlers = {
69
+ 'Get': grpc.unary_unary_rpc_method_handler(
70
+ servicer.Get,
71
+ request_deserializer=activities__pb2.ActivityGetRequest.FromString,
72
+ response_serializer=activities__pb2.ActivityGetResponse.SerializeToString,
73
+ ),
74
+ 'List': grpc.unary_unary_rpc_method_handler(
75
+ servicer.List,
76
+ request_deserializer=activities__pb2.ActivityListRequest.FromString,
77
+ response_serializer=activities__pb2.ActivityListResponse.SerializeToString,
78
+ ),
79
+ }
80
+ generic_handler = grpc.method_handlers_generic_handler(
81
+ 'v1.Activities', rpc_method_handlers)
82
+ server.add_generic_rpc_handlers((generic_handler,))
83
+
84
+
85
+ # This class is part of an EXPERIMENTAL API.
86
+ class Activities(object):
87
+ """An Activity is a record of an action taken against a strongDM deployment, e.g.
88
+ a user creation, resource deletion, sso configuration change, etc. The Activities
89
+ service is read-only.
90
+ """
91
+
92
+ @staticmethod
93
+ def Get(request,
94
+ target,
95
+ options=(),
96
+ channel_credentials=None,
97
+ call_credentials=None,
98
+ insecure=False,
99
+ compression=None,
100
+ wait_for_ready=None,
101
+ timeout=None,
102
+ metadata=None):
103
+ return grpc.experimental.unary_unary(request, target, '/v1.Activities/Get',
104
+ activities__pb2.ActivityGetRequest.SerializeToString,
105
+ activities__pb2.ActivityGetResponse.FromString,
106
+ options, channel_credentials,
107
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
108
+
109
+ @staticmethod
110
+ def List(request,
111
+ target,
112
+ options=(),
113
+ channel_credentials=None,
114
+ call_credentials=None,
115
+ insecure=False,
116
+ compression=None,
117
+ wait_for_ready=None,
118
+ timeout=None,
119
+ metadata=None):
120
+ return grpc.experimental.unary_unary(request, target, '/v1.Activities/List',
121
+ activities__pb2.ActivityListRequest.SerializeToString,
122
+ activities__pb2.ActivityListResponse.FromString,
123
+ options, channel_credentials,
124
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -0,0 +1,432 @@
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
+ # This file was generated by protogen. DO NOT EDIT.
17
+
18
+ import base64
19
+ import copy
20
+ import datetime
21
+ import grpc
22
+ import hashlib
23
+ import hmac
24
+ import random
25
+ import time
26
+ from . import svc
27
+ from . import plumbing
28
+
29
+ # These defaults are taken from AWS. Customization of these values
30
+ # is a future step in the API.
31
+ DEFAULT_MAX_RETRIES = 3
32
+ DEFAULT_BASE_RETRY_DELAY = 0.0030 # 30 ms
33
+ DEFAULT_MAX_RETRY_DELAY = 300 # 300 seconds
34
+ API_VERSION = '2021-08-23'
35
+ USER_AGENT = 'strongdm-sdk-python/3.7.0'
36
+
37
+
38
+ class Client:
39
+ '''Client interacts with the strongDM API.'''
40
+ def __init__(self,
41
+ api_access_key,
42
+ api_secret,
43
+ host='api.strongdm.com:443',
44
+ insecure=False,
45
+ retry_rate_limit_errors=True):
46
+ '''
47
+ Create a new Client.
48
+
49
+ - api_access_key: the access key to authenticate with strongDM
50
+ - api_secret: the secret key to authenticate with strongDM
51
+ '''
52
+ self.api_access_key = api_access_key.strip()
53
+ self.api_secret = base64.b64decode(api_secret.strip())
54
+ self.max_retries = DEFAULT_MAX_RETRIES
55
+ self.base_retry_delay = DEFAULT_BASE_RETRY_DELAY
56
+ self.max_retry_delay = DEFAULT_MAX_RETRY_DELAY
57
+ self.expose_rate_limit_errors = (not retry_rate_limit_errors)
58
+ self.snapshot_datetime = None
59
+ self._test_options = {}
60
+
61
+ try:
62
+ if insecure:
63
+ channel = grpc.insecure_channel(host)
64
+ else:
65
+ creds = grpc.ssl_channel_credentials()
66
+ channel = grpc.secure_channel(host, creds)
67
+ except Exception as e:
68
+ raise plumbing.convert_error_to_porcelain(e) from e
69
+ self.channel = channel
70
+ self.account_attachments = svc.AccountAttachments(channel, self)
71
+ '''
72
+ AccountAttachments assign an account to a role.
73
+
74
+ See `strongdm.svc.AccountAttachments`.
75
+ '''
76
+ self.account_attachments_history = svc.AccountAttachmentsHistory(
77
+ channel, self)
78
+ '''
79
+ AccountAttachmentsHistory records all changes to the state of an AccountAttachment.
80
+
81
+ See `strongdm.svc.AccountAttachmentsHistory`.
82
+ '''
83
+ self.account_grants = svc.AccountGrants(channel, self)
84
+ '''
85
+ AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
86
+
87
+ See `strongdm.svc.AccountGrants`.
88
+ '''
89
+ self.account_grants_history = svc.AccountGrantsHistory(channel, self)
90
+ '''
91
+ AccountGrantsHistory records all changes to the state of an AccountGrant.
92
+
93
+ See `strongdm.svc.AccountGrantsHistory`.
94
+ '''
95
+ self.account_permissions = svc.AccountPermissions(channel, self)
96
+ '''
97
+ AccountPermissions records the granular permissions accounts have, allowing them to execute
98
+ relevant commands via StrongDM's APIs.
99
+
100
+ See `strongdm.svc.AccountPermissions`.
101
+ '''
102
+ self.account_resources = svc.AccountResources(channel, self)
103
+ '''
104
+ AccountResources enumerates the resources to which accounts have access.
105
+ The AccountResources service is read-only.
106
+
107
+ See `strongdm.svc.AccountResources`.
108
+ '''
109
+ self.accounts = svc.Accounts(channel, self)
110
+ '''
111
+ Accounts are users that have access to strongDM. There are two types of accounts:
112
+ 1. **Users:** humans who are authenticated through username and password or SSO.
113
+ 2. **Service Accounts:** machines that are authenticated using a service token.
114
+
115
+ See `strongdm.svc.Accounts`.
116
+ '''
117
+ self.accounts_history = svc.AccountsHistory(channel, self)
118
+ '''
119
+ AccountsHistory records all changes to the state of an Account.
120
+
121
+ See `strongdm.svc.AccountsHistory`.
122
+ '''
123
+ self.activities = svc.Activities(channel, self)
124
+ '''
125
+ An Activity is a record of an action taken against a strongDM deployment, e.g.
126
+ a user creation, resource deletion, sso configuration change, etc. The Activities
127
+ service is read-only.
128
+
129
+ See `strongdm.svc.Activities`.
130
+ '''
131
+ self.control_panel = svc.ControlPanel(channel, self)
132
+ '''
133
+ ControlPanel contains all administrative controls.
134
+
135
+ See `strongdm.svc.ControlPanel`.
136
+ '''
137
+ self.nodes = svc.Nodes(channel, self)
138
+ '''
139
+ Nodes make up the strongDM network, and allow your users to connect securely to your resources. There are two types of nodes:
140
+ - **Gateways** are the entry points into network. They listen for connection from the strongDM client, and provide access to databases and servers.
141
+ - **Relays** are used to extend the strongDM network into segmented subnets. They provide access to databases and servers but do not listen for incoming connections.
142
+
143
+ See `strongdm.svc.Nodes`.
144
+ '''
145
+ self.nodes_history = svc.NodesHistory(channel, self)
146
+ '''
147
+ NodesHistory records all changes to the state of a Node.
148
+
149
+ See `strongdm.svc.NodesHistory`.
150
+ '''
151
+ self.organization_history = svc.OrganizationHistory(channel, self)
152
+ '''
153
+ OrganizationHistory records all changes to the state of an Organization.
154
+
155
+ See `strongdm.svc.OrganizationHistory`.
156
+ '''
157
+ self.queries = svc.Queries(channel, self)
158
+ '''
159
+ A Query is a record of a single client request to a resource, such as an SQL query.
160
+ Long-running SSH, RDP, or Kubernetes interactive sessions also count as queries.
161
+ The Queries service is read-only.
162
+
163
+ See `strongdm.svc.Queries`.
164
+ '''
165
+ self.remote_identities = svc.RemoteIdentities(channel, self)
166
+ '''
167
+ RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
168
+
169
+ See `strongdm.svc.RemoteIdentities`.
170
+ '''
171
+ self.remote_identities_history = svc.RemoteIdentitiesHistory(
172
+ channel, self)
173
+ '''
174
+ RemoteIdentitiesHistory records all changes to the state of a RemoteIdentity.
175
+
176
+ See `strongdm.svc.RemoteIdentitiesHistory`.
177
+ '''
178
+ self.remote_identity_groups = svc.RemoteIdentityGroups(channel, self)
179
+ '''
180
+ A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
181
+ An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
182
+
183
+ See `strongdm.svc.RemoteIdentityGroups`.
184
+ '''
185
+ self.remote_identity_groups_history = svc.RemoteIdentityGroupsHistory(
186
+ channel, self)
187
+ '''
188
+ RemoteIdentityGroupsHistory records all changes to the state of a RemoteIdentityGroup.
189
+
190
+ See `strongdm.svc.RemoteIdentityGroupsHistory`.
191
+ '''
192
+ self.replays = svc.Replays(channel, self)
193
+ '''
194
+ A Replay captures the data transferred over a long-running SSH, RDP, or Kubernetes interactive session
195
+ (otherwise referred to as a query). The Replays service is read-only.
196
+
197
+ See `strongdm.svc.Replays`.
198
+ '''
199
+ self.resources = svc.Resources(channel, self)
200
+ '''
201
+ Resources are databases, servers, clusters, websites, or clouds that strongDM
202
+ delegates access to.
203
+
204
+ See `strongdm.svc.Resources`.
205
+ '''
206
+ self.resources_history = svc.ResourcesHistory(channel, self)
207
+ '''
208
+ ResourcesHistory records all changes to the state of a Resource.
209
+
210
+ See `strongdm.svc.ResourcesHistory`.
211
+ '''
212
+ self.role_resources = svc.RoleResources(channel, self)
213
+ '''
214
+ RoleResources enumerates the resources to which roles have access.
215
+ The RoleResources service is read-only.
216
+
217
+ See `strongdm.svc.RoleResources`.
218
+ '''
219
+ self.role_resources_history = svc.RoleResourcesHistory(channel, self)
220
+ '''
221
+ RoleResourcesHistory records all changes to the state of a RoleResource.
222
+
223
+ See `strongdm.svc.RoleResourcesHistory`.
224
+ '''
225
+ self.roles = svc.Roles(channel, self)
226
+ '''
227
+ A Role has a list of access rules which determine which Resources the members
228
+ of the Role have access to. An Account can be a member of multiple Roles via
229
+ AccountAttachments.
230
+
231
+ See `strongdm.svc.Roles`.
232
+ '''
233
+ self.roles_history = svc.RolesHistory(channel, self)
234
+ '''
235
+ RolesHistory records all changes to the state of a Role.
236
+
237
+ See `strongdm.svc.RolesHistory`.
238
+ '''
239
+ self.secret_stores = svc.SecretStores(channel, self)
240
+ '''
241
+ SecretStores are servers where resource secrets (passwords, keys) are stored.
242
+
243
+ See `strongdm.svc.SecretStores`.
244
+ '''
245
+ self.secret_stores_history = svc.SecretStoresHistory(channel, self)
246
+ '''
247
+ SecretStoresHistory records all changes to the state of a SecretStore.
248
+
249
+ See `strongdm.svc.SecretStoresHistory`.
250
+ '''
251
+
252
+ def close(self):
253
+ '''Closes this Client and releases all resources held by it.
254
+
255
+ Closing the Client will immediately terminate all RPCs active with the
256
+ Client and it is not valid to invoke new RPCs with the Client.
257
+
258
+ This method is idempotent.
259
+ '''
260
+ self.channel.close()
261
+
262
+ def get_metadata(self, method_name, req):
263
+ return [
264
+ ('x-sdm-authentication', self.api_access_key),
265
+ ('x-sdm-signature', self.sign(method_name,
266
+ req.SerializeToString())),
267
+ ('x-sdm-api-version', API_VERSION),
268
+ ('x-sdm-user-agent', USER_AGENT),
269
+ ]
270
+
271
+ def sign(self, method_name, request_bytes):
272
+ def hmac_digest(key, msg_byte_string):
273
+ return hmac.new(key, msg=msg_byte_string,
274
+ digestmod=hashlib.sha256).digest()
275
+
276
+ current_utc_date = datetime.datetime.utcnow().strftime('%Y-%m-%d')
277
+ signing_key = hmac_digest(self.api_secret, current_utc_date.encode())
278
+ signing_key = hmac_digest(signing_key, b'sdm_api_v1')
279
+
280
+ hash = hashlib.sha256()
281
+
282
+ hash.update(method_name.encode())
283
+ hash.update(b'\n')
284
+ hash.update(request_bytes)
285
+
286
+ return base64.b64encode(hmac_digest(signing_key, hash.digest()))
287
+
288
+ def jitterSleep(self, iter):
289
+ dur_max = self.base_retry_delay * 2**iter
290
+ if (dur_max > self.max_retry_delay):
291
+ dur_max = self.max_retry_delay
292
+ # get a value between 0 and max
293
+ dur = random.random() * dur_max
294
+ time.sleep(dur)
295
+
296
+ def shouldRetry(self, iter, err):
297
+ if (iter >= self.max_retries - 1):
298
+ return False
299
+ if not isinstance(err, grpc.RpcError):
300
+ return True
301
+ if (not self.expose_rate_limit_errors
302
+ ) and err.code() == grpc.StatusCode.RESOURCE_EXHAUSTED:
303
+ porcelain_err = plumbing.convert_error_to_porcelain(err)
304
+ wait_until = porcelain_err.rate_limit.reset_at
305
+ now = datetime.datetime.now(datetime.timezone.utc)
306
+ sleep_for = (wait_until - now).total_seconds()
307
+ # If timezones or clock drift causes this calculation to fail,
308
+ # wait at most one minute.
309
+ if sleep_for < 0 or sleep_for > 60:
310
+ sleep_for = 60
311
+ time.sleep(sleep_for)
312
+ return True
313
+ return err.code() == grpc.StatusCode.INTERNAL or err.code(
314
+ ) == grpc.StatusCode.UNAVAILABLE
315
+
316
+ def snapshot_at(self, snapshot_datetime):
317
+ '''
318
+ Constructs a read-only client that will provide historical data from the provided timestamp.
319
+
320
+ See `SnapshotClient`.
321
+ '''
322
+ client = copy.copy(self)
323
+ client.snapshot_datetime = snapshot_datetime
324
+ client.account_attachments = svc.AccountAttachments(
325
+ client.channel, client)
326
+ client.account_grants = svc.AccountGrants(client.channel, client)
327
+ client.account_permissions = svc.AccountPermissions(
328
+ client.channel, client)
329
+ client.account_resources = svc.AccountResources(client.channel, client)
330
+ client.accounts = svc.Accounts(client.channel, client)
331
+ client.nodes = svc.Nodes(client.channel, client)
332
+ client.remote_identities = svc.RemoteIdentities(client.channel, client)
333
+ client.remote_identity_groups = svc.RemoteIdentityGroups(
334
+ client.channel, client)
335
+ client.resources = svc.Resources(client.channel, client)
336
+ client.role_resources = svc.RoleResources(client.channel, client)
337
+ client.roles = svc.Roles(client.channel, client)
338
+ client.secret_stores = svc.SecretStores(client.channel, client)
339
+ return SnapshotClient(client)
340
+
341
+
342
+ class SnapshotClient:
343
+ '''SnapshotClient exposes methods to query historical records at a provided timestamp.'''
344
+ def __init__(self, client):
345
+ self.account_attachments = svc.SnapshotAccountAttachments(
346
+ client.account_attachments)
347
+ '''
348
+ AccountAttachments assign an account to a role.
349
+
350
+ See `strongdm.svc.SnapshotAccountAttachments`.
351
+ '''
352
+ self.account_grants = svc.SnapshotAccountGrants(client.account_grants)
353
+ '''
354
+ AccountGrants assign a resource directly to an account, giving the account the permission to connect to that resource.
355
+
356
+ See `strongdm.svc.SnapshotAccountGrants`.
357
+ '''
358
+ self.account_permissions = svc.SnapshotAccountPermissions(
359
+ client.account_permissions)
360
+ '''
361
+ AccountPermissions records the granular permissions accounts have, allowing them to execute
362
+ relevant commands via StrongDM's APIs.
363
+
364
+ See `strongdm.svc.SnapshotAccountPermissions`.
365
+ '''
366
+ self.account_resources = svc.SnapshotAccountResources(
367
+ client.account_resources)
368
+ '''
369
+ AccountResources enumerates the resources to which accounts have access.
370
+ The AccountResources service is read-only.
371
+
372
+ See `strongdm.svc.SnapshotAccountResources`.
373
+ '''
374
+ self.accounts = svc.SnapshotAccounts(client.accounts)
375
+ '''
376
+ Accounts are users that have access to strongDM. There are two types of accounts:
377
+ 1. **Users:** humans who are authenticated through username and password or SSO.
378
+ 2. **Service Accounts:** machines that are authenticated using a service token.
379
+
380
+ See `strongdm.svc.SnapshotAccounts`.
381
+ '''
382
+ self.nodes = svc.SnapshotNodes(client.nodes)
383
+ '''
384
+ Nodes make up the strongDM network, and allow your users to connect securely to your resources. There are two types of nodes:
385
+ - **Gateways** are the entry points into network. They listen for connection from the strongDM client, and provide access to databases and servers.
386
+ - **Relays** are used to extend the strongDM network into segmented subnets. They provide access to databases and servers but do not listen for incoming connections.
387
+
388
+ See `strongdm.svc.SnapshotNodes`.
389
+ '''
390
+ self.remote_identities = svc.SnapshotRemoteIdentities(
391
+ client.remote_identities)
392
+ '''
393
+ RemoteIdentities assign a resource directly to an account, giving the account the permission to connect to that resource.
394
+
395
+ See `strongdm.svc.SnapshotRemoteIdentities`.
396
+ '''
397
+ self.remote_identity_groups = svc.SnapshotRemoteIdentityGroups(
398
+ client.remote_identity_groups)
399
+ '''
400
+ A RemoteIdentityGroup is a named grouping of Remote Identities for Accounts.
401
+ An Account's relationship to a RemoteIdentityGroup is defined via RemoteIdentity objects.
402
+
403
+ See `strongdm.svc.SnapshotRemoteIdentityGroups`.
404
+ '''
405
+ self.resources = svc.SnapshotResources(client.resources)
406
+ '''
407
+ Resources are databases, servers, clusters, websites, or clouds that strongDM
408
+ delegates access to.
409
+
410
+ See `strongdm.svc.SnapshotResources`.
411
+ '''
412
+ self.role_resources = svc.SnapshotRoleResources(client.role_resources)
413
+ '''
414
+ RoleResources enumerates the resources to which roles have access.
415
+ The RoleResources service is read-only.
416
+
417
+ See `strongdm.svc.SnapshotRoleResources`.
418
+ '''
419
+ self.roles = svc.SnapshotRoles(client.roles)
420
+ '''
421
+ A Role has a list of access rules which determine which Resources the members
422
+ of the Role have access to. An Account can be a member of multiple Roles via
423
+ AccountAttachments.
424
+
425
+ See `strongdm.svc.SnapshotRoles`.
426
+ '''
427
+ self.secret_stores = svc.SnapshotSecretStores(client.secret_stores)
428
+ '''
429
+ SecretStores are servers where resource secrets (passwords, keys) are stored.
430
+
431
+ See `strongdm.svc.SnapshotSecretStores`.
432
+ '''