clear-skies 1.19.22__py3-none-any.whl → 2.0.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clear_skies-2.0.23.dist-info/METADATA +76 -0
- clear_skies-2.0.23.dist-info/RECORD +265 -0
- {clear_skies-1.19.22.dist-info → clear_skies-2.0.23.dist-info}/WHEEL +1 -1
- clearskies/__init__.py +37 -21
- clearskies/action.py +7 -0
- clearskies/authentication/__init__.py +9 -38
- clearskies/authentication/authentication.py +44 -0
- clearskies/authentication/authorization.py +14 -8
- clearskies/authentication/authorization_pass_through.py +22 -0
- clearskies/authentication/jwks.py +135 -58
- clearskies/authentication/public.py +3 -26
- clearskies/authentication/secret_bearer.py +515 -44
- clearskies/autodoc/formats/oai3_json/__init__.py +2 -2
- clearskies/autodoc/formats/oai3_json/oai3_json.py +11 -9
- clearskies/autodoc/formats/oai3_json/parameter.py +6 -3
- clearskies/autodoc/formats/oai3_json/request.py +7 -5
- clearskies/autodoc/formats/oai3_json/response.py +7 -4
- clearskies/autodoc/formats/oai3_json/schema/object.py +10 -1
- clearskies/autodoc/request/__init__.py +2 -0
- clearskies/autodoc/request/header.py +4 -6
- clearskies/autodoc/request/json_body.py +4 -6
- clearskies/autodoc/request/parameter.py +8 -0
- clearskies/autodoc/request/request.py +16 -4
- clearskies/autodoc/request/url_parameter.py +4 -6
- clearskies/autodoc/request/url_path.py +4 -6
- clearskies/autodoc/schema/__init__.py +4 -2
- clearskies/autodoc/schema/array.py +5 -6
- clearskies/autodoc/schema/boolean.py +4 -10
- clearskies/autodoc/schema/date.py +0 -3
- clearskies/autodoc/schema/datetime.py +1 -4
- clearskies/autodoc/schema/double.py +0 -3
- clearskies/autodoc/schema/enum.py +4 -2
- clearskies/autodoc/schema/integer.py +4 -9
- clearskies/autodoc/schema/long.py +0 -3
- clearskies/autodoc/schema/number.py +4 -9
- clearskies/autodoc/schema/object.py +5 -7
- clearskies/autodoc/schema/password.py +0 -3
- clearskies/autodoc/schema/schema.py +11 -0
- clearskies/autodoc/schema/string.py +4 -10
- clearskies/backends/__init__.py +56 -17
- clearskies/backends/api_backend.py +1128 -166
- clearskies/backends/backend.py +54 -85
- clearskies/backends/cursor_backend.py +246 -191
- clearskies/backends/memory_backend.py +514 -208
- clearskies/backends/secrets_backend.py +68 -31
- clearskies/column.py +1221 -0
- clearskies/columns/__init__.py +71 -0
- clearskies/columns/audit.py +306 -0
- clearskies/columns/belongs_to_id.py +478 -0
- clearskies/columns/belongs_to_model.py +129 -0
- clearskies/columns/belongs_to_self.py +109 -0
- clearskies/columns/boolean.py +110 -0
- clearskies/columns/category_tree.py +273 -0
- clearskies/columns/category_tree_ancestors.py +51 -0
- clearskies/columns/category_tree_children.py +126 -0
- clearskies/columns/category_tree_descendants.py +48 -0
- clearskies/columns/created.py +92 -0
- clearskies/columns/created_by_authorization_data.py +114 -0
- clearskies/columns/created_by_header.py +103 -0
- clearskies/columns/created_by_ip.py +90 -0
- clearskies/columns/created_by_routing_data.py +102 -0
- clearskies/columns/created_by_user_agent.py +89 -0
- clearskies/columns/date.py +232 -0
- clearskies/columns/datetime.py +284 -0
- clearskies/columns/email.py +78 -0
- clearskies/columns/float.py +149 -0
- clearskies/columns/has_many.py +529 -0
- clearskies/columns/has_many_self.py +62 -0
- clearskies/columns/has_one.py +21 -0
- clearskies/columns/integer.py +158 -0
- clearskies/columns/json.py +126 -0
- clearskies/columns/many_to_many_ids.py +335 -0
- clearskies/columns/many_to_many_ids_with_data.py +274 -0
- clearskies/columns/many_to_many_models.py +156 -0
- clearskies/columns/many_to_many_pivots.py +132 -0
- clearskies/columns/phone.py +162 -0
- clearskies/columns/select.py +95 -0
- clearskies/columns/string.py +102 -0
- clearskies/columns/timestamp.py +164 -0
- clearskies/columns/updated.py +107 -0
- clearskies/columns/uuid.py +83 -0
- clearskies/configs/README.md +105 -0
- clearskies/configs/__init__.py +170 -0
- clearskies/configs/actions.py +43 -0
- clearskies/configs/any.py +15 -0
- clearskies/configs/any_dict.py +24 -0
- clearskies/configs/any_dict_or_callable.py +25 -0
- clearskies/configs/authentication.py +23 -0
- clearskies/configs/authorization.py +23 -0
- clearskies/configs/boolean.py +18 -0
- clearskies/configs/boolean_or_callable.py +20 -0
- clearskies/configs/callable_config.py +20 -0
- clearskies/configs/columns.py +34 -0
- clearskies/configs/conditions.py +30 -0
- clearskies/configs/config.py +26 -0
- clearskies/configs/datetime.py +20 -0
- clearskies/configs/datetime_or_callable.py +21 -0
- clearskies/configs/email.py +10 -0
- clearskies/configs/email_list.py +17 -0
- clearskies/configs/email_list_or_callable.py +17 -0
- clearskies/configs/email_or_email_list_or_callable.py +59 -0
- clearskies/configs/endpoint.py +23 -0
- clearskies/configs/endpoint_list.py +29 -0
- clearskies/configs/float.py +18 -0
- clearskies/configs/float_or_callable.py +20 -0
- clearskies/configs/headers.py +28 -0
- clearskies/configs/integer.py +18 -0
- clearskies/configs/integer_or_callable.py +20 -0
- clearskies/configs/joins.py +30 -0
- clearskies/configs/list_any_dict.py +32 -0
- clearskies/configs/list_any_dict_or_callable.py +33 -0
- clearskies/configs/model_class.py +35 -0
- clearskies/configs/model_column.py +67 -0
- clearskies/configs/model_columns.py +58 -0
- clearskies/configs/model_destination_name.py +26 -0
- clearskies/configs/model_to_id_column.py +45 -0
- clearskies/configs/readable_model_column.py +11 -0
- clearskies/configs/readable_model_columns.py +11 -0
- clearskies/configs/schema.py +23 -0
- clearskies/configs/searchable_model_columns.py +11 -0
- clearskies/configs/security_headers.py +39 -0
- clearskies/configs/select.py +28 -0
- clearskies/configs/select_list.py +49 -0
- clearskies/configs/string.py +31 -0
- clearskies/configs/string_dict.py +34 -0
- clearskies/configs/string_list.py +47 -0
- clearskies/configs/string_list_or_callable.py +48 -0
- clearskies/configs/string_or_callable.py +18 -0
- clearskies/configs/timedelta.py +20 -0
- clearskies/configs/timezone.py +20 -0
- clearskies/configs/url.py +25 -0
- clearskies/configs/validators.py +45 -0
- clearskies/configs/writeable_model_column.py +11 -0
- clearskies/configs/writeable_model_columns.py +11 -0
- clearskies/configurable.py +78 -0
- clearskies/contexts/__init__.py +8 -8
- clearskies/contexts/cli.py +129 -43
- clearskies/contexts/context.py +93 -56
- clearskies/contexts/wsgi.py +79 -33
- clearskies/contexts/wsgi_ref.py +87 -0
- clearskies/cursors/__init__.py +7 -0
- clearskies/cursors/cursor.py +166 -0
- clearskies/cursors/from_environment/__init__.py +5 -0
- clearskies/cursors/from_environment/mysql.py +51 -0
- clearskies/cursors/from_environment/postgresql.py +49 -0
- clearskies/cursors/from_environment/sqlite.py +35 -0
- clearskies/cursors/mysql.py +61 -0
- clearskies/cursors/postgresql.py +61 -0
- clearskies/cursors/sqlite.py +62 -0
- clearskies/decorators.py +33 -0
- clearskies/decorators.pyi +10 -0
- clearskies/di/__init__.py +11 -7
- clearskies/di/additional_config.py +117 -3
- clearskies/di/additional_config_auto_import.py +12 -0
- clearskies/di/di.py +717 -126
- clearskies/di/inject/__init__.py +23 -0
- clearskies/di/inject/akeyless_sdk.py +16 -0
- clearskies/di/inject/by_class.py +24 -0
- clearskies/di/inject/by_name.py +22 -0
- clearskies/di/inject/di.py +16 -0
- clearskies/di/inject/environment.py +15 -0
- clearskies/di/inject/input_output.py +19 -0
- clearskies/di/inject/now.py +16 -0
- clearskies/di/inject/requests.py +16 -0
- clearskies/di/inject/secrets.py +15 -0
- clearskies/di/inject/utcnow.py +16 -0
- clearskies/di/inject/uuid.py +16 -0
- clearskies/di/injectable.py +32 -0
- clearskies/di/injectable_properties.py +131 -0
- clearskies/end.py +219 -0
- clearskies/endpoint.py +1303 -0
- clearskies/endpoint_group.py +333 -0
- clearskies/endpoints/__init__.py +25 -0
- clearskies/endpoints/advanced_search.py +519 -0
- clearskies/endpoints/callable.py +382 -0
- clearskies/endpoints/create.py +201 -0
- clearskies/endpoints/delete.py +133 -0
- clearskies/endpoints/get.py +267 -0
- clearskies/endpoints/health_check.py +181 -0
- clearskies/endpoints/list.py +567 -0
- clearskies/endpoints/restful_api.py +417 -0
- clearskies/endpoints/schema.py +185 -0
- clearskies/endpoints/simple_search.py +279 -0
- clearskies/endpoints/update.py +188 -0
- clearskies/environment.py +7 -3
- clearskies/exceptions/__init__.py +19 -0
- clearskies/{handlers/exceptions/input_error.py → exceptions/input_errors.py} +1 -1
- clearskies/exceptions/missing_dependency.py +2 -0
- clearskies/exceptions/moved_permanently.py +3 -0
- clearskies/exceptions/moved_temporarily.py +3 -0
- clearskies/functional/__init__.py +2 -2
- clearskies/functional/json.py +47 -0
- clearskies/functional/routing.py +92 -0
- clearskies/functional/string.py +19 -11
- clearskies/functional/validations.py +61 -9
- clearskies/input_outputs/__init__.py +9 -7
- clearskies/input_outputs/cli.py +135 -152
- clearskies/input_outputs/exceptions/__init__.py +6 -1
- clearskies/input_outputs/headers.py +54 -0
- clearskies/input_outputs/input_output.py +77 -123
- clearskies/input_outputs/programmatic.py +62 -0
- clearskies/input_outputs/wsgi.py +36 -48
- clearskies/model.py +1894 -199
- clearskies/query/__init__.py +12 -0
- clearskies/query/condition.py +228 -0
- clearskies/query/join.py +136 -0
- clearskies/query/query.py +193 -0
- clearskies/query/sort.py +27 -0
- clearskies/schema.py +82 -0
- clearskies/secrets/__init__.py +4 -31
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +15 -4
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +11 -5
- clearskies/secrets/akeyless.py +421 -155
- clearskies/secrets/exceptions/__init__.py +7 -1
- clearskies/secrets/exceptions/not_found_error.py +2 -0
- clearskies/secrets/exceptions/permissions_error.py +2 -0
- clearskies/secrets/secrets.py +12 -11
- clearskies/security_header.py +17 -0
- clearskies/security_headers/__init__.py +8 -8
- clearskies/security_headers/cache_control.py +47 -109
- clearskies/security_headers/cors.py +38 -92
- clearskies/security_headers/csp.py +76 -150
- clearskies/security_headers/hsts.py +14 -15
- clearskies/typing.py +11 -0
- clearskies/validator.py +36 -0
- clearskies/validators/__init__.py +33 -0
- clearskies/validators/after_column.py +61 -0
- clearskies/validators/before_column.py +15 -0
- clearskies/validators/in_the_future.py +29 -0
- clearskies/validators/in_the_future_at_least.py +13 -0
- clearskies/validators/in_the_future_at_most.py +12 -0
- clearskies/validators/in_the_past.py +29 -0
- clearskies/validators/in_the_past_at_least.py +12 -0
- clearskies/validators/in_the_past_at_most.py +12 -0
- clearskies/validators/maximum_length.py +25 -0
- clearskies/validators/maximum_value.py +28 -0
- clearskies/validators/minimum_length.py +25 -0
- clearskies/validators/minimum_value.py +28 -0
- clearskies/{input_requirements → validators}/required.py +18 -9
- clearskies/validators/timedelta.py +58 -0
- clearskies/validators/unique.py +28 -0
- clear_skies-1.19.22.dist-info/METADATA +0 -46
- clear_skies-1.19.22.dist-info/RECORD +0 -206
- clearskies/application.py +0 -29
- clearskies/authentication/auth0_jwks.py +0 -118
- clearskies/authentication/auth_exception.py +0 -2
- clearskies/authentication/jwks_jwcrypto.py +0 -39
- clearskies/backends/example_backend.py +0 -43
- clearskies/backends/file_backend.py +0 -48
- clearskies/backends/json_backend.py +0 -7
- clearskies/backends/restful_api_advanced_search_backend.py +0 -138
- clearskies/binding_config.py +0 -16
- clearskies/column_types/__init__.py +0 -184
- clearskies/column_types/audit.py +0 -235
- clearskies/column_types/belongs_to.py +0 -250
- clearskies/column_types/boolean.py +0 -60
- clearskies/column_types/category_tree.py +0 -226
- clearskies/column_types/column.py +0 -373
- clearskies/column_types/created.py +0 -26
- clearskies/column_types/created_by_authorization_data.py +0 -26
- clearskies/column_types/created_by_header.py +0 -24
- clearskies/column_types/created_by_ip.py +0 -17
- clearskies/column_types/created_by_routing_data.py +0 -25
- clearskies/column_types/created_by_user_agent.py +0 -17
- clearskies/column_types/created_micro.py +0 -26
- clearskies/column_types/datetime.py +0 -108
- clearskies/column_types/datetime_micro.py +0 -12
- clearskies/column_types/email.py +0 -18
- clearskies/column_types/float.py +0 -43
- clearskies/column_types/has_many.py +0 -139
- clearskies/column_types/integer.py +0 -41
- clearskies/column_types/json.py +0 -25
- clearskies/column_types/many_to_many.py +0 -278
- clearskies/column_types/many_to_many_with_data.py +0 -162
- clearskies/column_types/select.py +0 -11
- clearskies/column_types/string.py +0 -24
- clearskies/column_types/updated.py +0 -24
- clearskies/column_types/updated_micro.py +0 -24
- clearskies/column_types/uuid.py +0 -25
- clearskies/columns.py +0 -123
- clearskies/condition_parser.py +0 -172
- clearskies/contexts/build_context.py +0 -54
- clearskies/contexts/convert_to_application.py +0 -190
- clearskies/contexts/extract_handler.py +0 -37
- clearskies/contexts/test.py +0 -94
- clearskies/decorators/__init__.py +0 -39
- clearskies/decorators/auth0_jwks.py +0 -22
- clearskies/decorators/authorization.py +0 -10
- clearskies/decorators/binding_classes.py +0 -9
- clearskies/decorators/binding_modules.py +0 -9
- clearskies/decorators/bindings.py +0 -9
- clearskies/decorators/create.py +0 -10
- clearskies/decorators/delete.py +0 -10
- clearskies/decorators/docs.py +0 -14
- clearskies/decorators/get.py +0 -10
- clearskies/decorators/jwks.py +0 -26
- clearskies/decorators/merge.py +0 -124
- clearskies/decorators/patch.py +0 -10
- clearskies/decorators/post.py +0 -10
- clearskies/decorators/public.py +0 -11
- clearskies/decorators/response_headers.py +0 -10
- clearskies/decorators/return_raw_response.py +0 -9
- clearskies/decorators/schema.py +0 -10
- clearskies/decorators/secret_bearer.py +0 -24
- clearskies/decorators/security_headers.py +0 -10
- clearskies/di/standard_dependencies.py +0 -140
- clearskies/di/test_module/__init__.py +0 -6
- clearskies/di/test_module/another_module/__init__.py +0 -2
- clearskies/di/test_module/module_class.py +0 -5
- clearskies/handlers/__init__.py +0 -41
- clearskies/handlers/advanced_search.py +0 -271
- clearskies/handlers/base.py +0 -473
- clearskies/handlers/callable.py +0 -189
- clearskies/handlers/create.py +0 -35
- clearskies/handlers/crud_by_method.py +0 -18
- clearskies/handlers/database_connector.py +0 -32
- clearskies/handlers/delete.py +0 -61
- clearskies/handlers/exceptions/__init__.py +0 -5
- clearskies/handlers/exceptions/not_found.py +0 -3
- clearskies/handlers/get.py +0 -156
- clearskies/handlers/health_check.py +0 -59
- clearskies/handlers/input_processing.py +0 -79
- clearskies/handlers/list.py +0 -530
- clearskies/handlers/mygrations.py +0 -82
- clearskies/handlers/request_method_routing.py +0 -47
- clearskies/handlers/restful_api.py +0 -218
- clearskies/handlers/routing.py +0 -62
- clearskies/handlers/schema_helper.py +0 -128
- clearskies/handlers/simple_routing.py +0 -204
- clearskies/handlers/simple_routing_route.py +0 -192
- clearskies/handlers/simple_search.py +0 -136
- clearskies/handlers/update.py +0 -96
- clearskies/handlers/write.py +0 -193
- clearskies/input_requirements/__init__.py +0 -68
- clearskies/input_requirements/after.py +0 -36
- clearskies/input_requirements/before.py +0 -36
- clearskies/input_requirements/in_the_future_at_least.py +0 -19
- clearskies/input_requirements/in_the_future_at_most.py +0 -19
- clearskies/input_requirements/in_the_past_at_least.py +0 -19
- clearskies/input_requirements/in_the_past_at_most.py +0 -19
- clearskies/input_requirements/maximum_length.py +0 -19
- clearskies/input_requirements/minimum_length.py +0 -22
- clearskies/input_requirements/requirement.py +0 -25
- clearskies/input_requirements/time_delta.py +0 -38
- clearskies/input_requirements/unique.py +0 -18
- clearskies/mocks/__init__.py +0 -7
- clearskies/mocks/input_output.py +0 -124
- clearskies/mocks/models.py +0 -142
- clearskies/models.py +0 -345
- clearskies/security_headers/base.py +0 -12
- clearskies/tests/simple_api/models/__init__.py +0 -2
- clearskies/tests/simple_api/models/status.py +0 -23
- clearskies/tests/simple_api/models/user.py +0 -21
- clearskies/tests/simple_api/users_api.py +0 -64
- {clear_skies-1.19.22.dist-info → clear_skies-2.0.23.dist-info/licenses}/LICENSE +0 -0
- /clearskies/{contexts/bash.py → autodoc/py.typed} +0 -0
- /clearskies/{handlers/exceptions → exceptions}/authentication.py +0 -0
- /clearskies/{handlers/exceptions → exceptions}/authorization.py +0 -0
- /clearskies/{handlers/exceptions → exceptions}/client_error.py +0 -0
- /clearskies/{secrets/exceptions → exceptions}/not_found.py +0 -0
- /clearskies/{tests/__init__.py → input_outputs/py.typed} +0 -0
- /clearskies/{tests/simple_api/__init__.py → py.typed} +0 -0
clearskies/secrets/akeyless.py
CHANGED
|
@@ -1,170 +1,371 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import datetime
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
4
|
+
import logging
|
|
5
|
+
from types import ModuleType
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from clearskies import configs, secrets
|
|
9
|
+
from clearskies.decorators import parameters_to_properties
|
|
10
|
+
from clearskies.di import inject
|
|
11
|
+
from clearskies.functional.json import get_nested_attribute
|
|
12
|
+
from clearskies.secrets.exceptions import PermissionsError
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from akeyless import ListItemsOutput, V2Api # type: ignore[import-untyped]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Akeyless(secrets.Secrets):
|
|
19
|
+
"""
|
|
20
|
+
Backend for managing secrets using the Akeyless Vault.
|
|
21
|
+
|
|
22
|
+
This class provides integration with Akeyless vault services, allowing you to store, retrieve,
|
|
23
|
+
and manage secrets. It supports different types of secrets (static, dynamic, rotated) and
|
|
24
|
+
includes authentication mechanisms for AWS IAM, SAML, and JWT.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
HTTP client for making API requests
|
|
29
|
+
"""
|
|
30
|
+
requests = inject.Requests()
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
Environment configuration for retrieving environment variables
|
|
34
|
+
"""
|
|
35
|
+
environment = inject.Environment()
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
The Akeyless SDK module injected by the dependency injection system
|
|
39
|
+
"""
|
|
40
|
+
akeyless: ModuleType = inject.ByName("akeyless_sdk") # type: ignore
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
The access ID for the Akeyless service
|
|
44
|
+
|
|
45
|
+
This must match the pattern p-[0-9a-zA-Z]+ (e.g., "p-abc123")
|
|
46
|
+
"""
|
|
47
|
+
access_id = configs.String(required=True, regexp=r"^p-[\d\w]+$")
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
The authentication method to use
|
|
51
|
+
|
|
52
|
+
Must be one of "aws_iam", "saml", or "jwt"
|
|
53
|
+
"""
|
|
54
|
+
access_type = configs.Select(["aws_iam", "saml", "jwt"], required=True)
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
The Akeyless API host to connect to
|
|
58
|
+
|
|
59
|
+
Defaults to "https://api.akeyless.io"
|
|
60
|
+
"""
|
|
61
|
+
api_host = configs.String(default="https://api.akeyless.io")
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
The environment variable key that contains the JWT when using JWT authentication
|
|
65
|
+
|
|
66
|
+
This is required when access_type is "jwt"
|
|
67
|
+
"""
|
|
68
|
+
jwt_env_key = configs.String(required=False)
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
The SAML profile name when using SAML authentication
|
|
72
|
+
|
|
73
|
+
Must match the pattern [0-9a-zA-Z-]+ if provided
|
|
74
|
+
"""
|
|
75
|
+
profile = configs.String(regexp=r"^[\d\w-]+$", default="default")
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
Whether to automatically guess the secret type
|
|
79
|
+
|
|
80
|
+
When enabled, the system will check the secret type (static, dynamic, rotated)
|
|
81
|
+
and call the appropriate method to retrieve it.
|
|
82
|
+
"""
|
|
83
|
+
auto_guess_type = configs.Boolean(default=False)
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
When the current token expires
|
|
87
|
+
"""
|
|
88
|
+
_token_refresh: datetime.datetime # type: ignore
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
The current authentication token
|
|
92
|
+
"""
|
|
93
|
+
_token: str
|
|
94
|
+
|
|
95
|
+
"""
|
|
96
|
+
The configured V2Api client
|
|
97
|
+
"""
|
|
98
|
+
_api: V2Api
|
|
99
|
+
|
|
100
|
+
@parameters_to_properties
|
|
101
|
+
def __init__(
|
|
102
|
+
self,
|
|
103
|
+
access_id: str,
|
|
104
|
+
access_type: str,
|
|
105
|
+
jwt_env_key: str | None = None,
|
|
106
|
+
api_host: str | None = None,
|
|
107
|
+
profile: str | None = None,
|
|
108
|
+
auto_guess_type: bool = False,
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
Initialize the Akeyless backend with the specified configuration.
|
|
112
|
+
|
|
113
|
+
The access_id must be provided and follow the format p-[0-9a-zA-Z]+. The access_type must be
|
|
114
|
+
one of "aws_iam", "saml", or "jwt". If using JWT authentication, jwt_env_key must be provided.
|
|
115
|
+
"""
|
|
116
|
+
self.finalize_and_validate_configuration()
|
|
117
|
+
self.logger = logging.getLogger(self.__class__.__name__)
|
|
118
|
+
|
|
119
|
+
def configure(self) -> None:
|
|
120
|
+
"""
|
|
121
|
+
Perform additional configuration validation.
|
|
122
|
+
|
|
123
|
+
Ensures that when using JWT authentication, the jwt_env_key is provided. Raises ValueError
|
|
124
|
+
if access_type is "jwt" and jwt_env_key is not provided.
|
|
125
|
+
"""
|
|
126
|
+
if self.access_type == "jwt" and not self.jwt_env_key:
|
|
127
|
+
raise ValueError("When using the JWT access type for Akeyless you must provide jwt_env_key")
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def api(self) -> V2Api:
|
|
131
|
+
"""
|
|
132
|
+
Get the configured V2Api client.
|
|
133
|
+
|
|
134
|
+
Creates a new API client if one doesn't exist yet, using the configured api_host.
|
|
135
|
+
"""
|
|
136
|
+
if not hasattr(self, "_api"):
|
|
137
|
+
configuration = self.akeyless.Configuration(host=self.api_host)
|
|
138
|
+
self._api = self.akeyless.V2Api(self.akeyless.ApiClient(configuration))
|
|
139
|
+
return self._api
|
|
140
|
+
|
|
141
|
+
def create(self, path: str, value: Any) -> bool:
|
|
142
|
+
"""
|
|
143
|
+
Create a new secret at the given path.
|
|
144
|
+
|
|
145
|
+
Checks permissions before creating the secret and raises PermissionsError if the user doesn't
|
|
146
|
+
have write permission for the path. The value is converted to a string before storage.
|
|
147
|
+
"""
|
|
148
|
+
if not "write" in self.describe_permissions(path):
|
|
149
|
+
raise PermissionsError(f"You do not have permission the secret '{path}'")
|
|
150
|
+
|
|
151
|
+
res = self.api.create_secret(self.akeyless.CreateSecret(name=path, value=str(value), token=self._get_token()))
|
|
89
152
|
return True
|
|
90
153
|
|
|
91
|
-
def get(
|
|
92
|
-
self
|
|
154
|
+
def get(
|
|
155
|
+
self,
|
|
156
|
+
path: str,
|
|
157
|
+
silent_if_not_found: bool = False,
|
|
158
|
+
json_attribute: str | None = None,
|
|
159
|
+
args: dict[str, Any] | None = None,
|
|
160
|
+
) -> str:
|
|
161
|
+
"""
|
|
162
|
+
Get the secret at the given path.
|
|
163
|
+
|
|
164
|
+
When auto_guess_type is enabled, this method automatically determines if the secret is static,
|
|
165
|
+
dynamic, or rotated and calls the appropriate method to retrieve it. If silent_if_not_found is
|
|
166
|
+
True, returns an empty string when the secret is not found. If json_attribute is provided,
|
|
167
|
+
treats the secret as JSON and returns the specified attribute.
|
|
168
|
+
"""
|
|
169
|
+
if not self.auto_guess_type:
|
|
170
|
+
return self.get_static_secret(path, silent_if_not_found=silent_if_not_found, json_attribute=json_attribute)
|
|
93
171
|
|
|
94
172
|
try:
|
|
95
|
-
|
|
173
|
+
secret = self.describe_secret(path)
|
|
96
174
|
except Exception as e:
|
|
97
|
-
if e.status == 404:
|
|
175
|
+
if e.status == 404: # type: ignore
|
|
98
176
|
if silent_if_not_found:
|
|
99
|
-
return
|
|
100
|
-
raise
|
|
101
|
-
|
|
102
|
-
|
|
177
|
+
return ""
|
|
178
|
+
raise e
|
|
179
|
+
else:
|
|
180
|
+
raise ValueError(
|
|
181
|
+
f"describe-secret call failed for path {path}: perhaps a permissions issue? Akeless says {e}"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
self.logger.debug(f"Auto-detected secret type '{secret.item_type}' for secret '{path}'")
|
|
185
|
+
match secret.item_type.lower():
|
|
186
|
+
case "dynamic_secret":
|
|
187
|
+
return str(
|
|
188
|
+
self.get_dynamic_secret(
|
|
189
|
+
path,
|
|
190
|
+
json_attribute=json_attribute,
|
|
191
|
+
args=args,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
case "rotated_secret":
|
|
195
|
+
return str(self.get_rotated_secret(path, json_attribute=json_attribute, args=args))
|
|
196
|
+
case "static_secret":
|
|
197
|
+
return self.get_static_secret(
|
|
198
|
+
path, json_attribute=json_attribute, silent_if_not_found=silent_if_not_found
|
|
199
|
+
)
|
|
200
|
+
case _:
|
|
201
|
+
raise ValueError(f"Unsupported secret type for auto-detection: '{secret.item_type}'")
|
|
202
|
+
|
|
203
|
+
def get_static_secret(self, path: str, silent_if_not_found: bool = False, json_attribute: str | None = None) -> str:
|
|
204
|
+
"""
|
|
205
|
+
Get a static secret from the given path.
|
|
206
|
+
|
|
207
|
+
Checks permissions before retrieving the secret and raises PermissionsError if the user doesn't
|
|
208
|
+
have read permission. If silent_if_not_found is True, returns an empty string when the secret
|
|
209
|
+
is not found. If json_attribute is provided, treats the secret as JSON and returns the specified attribute.
|
|
210
|
+
"""
|
|
211
|
+
if not "read" in self.describe_permissions(path):
|
|
212
|
+
raise PermissionsError(f"You do not have permission the secret '{path}'")
|
|
103
213
|
|
|
104
|
-
|
|
105
|
-
|
|
214
|
+
try:
|
|
215
|
+
res: dict[str, object] = self.api.get_secret_value( # type: ignore
|
|
216
|
+
self.akeyless.GetSecretValue(
|
|
217
|
+
names=[path], token=self._get_token(), json=True if json_attribute else False
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
except Exception as e:
|
|
221
|
+
if e.status == 404: # type: ignore
|
|
222
|
+
if silent_if_not_found:
|
|
223
|
+
return ""
|
|
224
|
+
raise KeyError(f"Secret '{path}' not found")
|
|
225
|
+
raise e
|
|
226
|
+
if json_attribute:
|
|
227
|
+
return get_nested_attribute(res[path], json_attribute) # type: ignore
|
|
228
|
+
return str(res[path])
|
|
229
|
+
|
|
230
|
+
def get_dynamic_secret(
|
|
231
|
+
self, path: str, json_attribute: str | None = None, args: dict[str, Any] | None = None
|
|
232
|
+
) -> Any:
|
|
233
|
+
"""
|
|
234
|
+
Get a dynamic secret from the given path.
|
|
235
|
+
|
|
236
|
+
Dynamic secrets are generated on-demand, such as database credentials. Checks permissions
|
|
237
|
+
before retrieving the secret and raises PermissionsError if the user doesn't have read
|
|
238
|
+
permission. If json_attribute is provided, treats the result as JSON and returns the
|
|
239
|
+
specified attribute.
|
|
240
|
+
"""
|
|
241
|
+
if not "read" in self.describe_permissions(path):
|
|
242
|
+
raise PermissionsError(f"You do not have permission the secret '{path}'")
|
|
106
243
|
|
|
107
244
|
kwargs = {
|
|
108
245
|
"name": path,
|
|
109
246
|
"token": self._get_token(),
|
|
110
247
|
}
|
|
111
248
|
if args:
|
|
112
|
-
kwargs["args"] = args
|
|
113
|
-
|
|
114
|
-
|
|
249
|
+
kwargs["args"] = args # type: ignore
|
|
250
|
+
res: dict[str, Any] = self.api.get_dynamic_secret_value(self.akeyless.GetDynamicSecretValue(**kwargs)) # type: ignore
|
|
251
|
+
if json_attribute:
|
|
252
|
+
return get_nested_attribute(res, json_attribute)
|
|
115
253
|
return res
|
|
116
254
|
|
|
117
|
-
def get_rotated_secret(
|
|
118
|
-
self
|
|
255
|
+
def get_rotated_secret(
|
|
256
|
+
self, path: str, json_attribute: str | None = None, args: dict[str, Any] | None = None
|
|
257
|
+
) -> Any:
|
|
258
|
+
"""
|
|
259
|
+
Get a rotated secret from the given path.
|
|
260
|
+
|
|
261
|
+
Rotated secrets are automatically replaced on a schedule. Checks permissions before
|
|
262
|
+
retrieving the secret and raises PermissionsError if the user doesn't have read
|
|
263
|
+
permission. If json_attribute is provided, treats the result as JSON and returns the
|
|
264
|
+
specified attribute.
|
|
265
|
+
"""
|
|
266
|
+
if not "read" in self.describe_permissions(path):
|
|
267
|
+
raise PermissionsError(f"You do not have permission the secret '{path}'")
|
|
119
268
|
|
|
120
269
|
kwargs = {
|
|
121
270
|
"names": path,
|
|
122
271
|
"token": self._get_token(),
|
|
272
|
+
"json": True if json_attribute else False,
|
|
123
273
|
}
|
|
124
274
|
if args:
|
|
125
|
-
kwargs["args"] = args
|
|
275
|
+
kwargs["args"] = args # type: ignore
|
|
126
276
|
|
|
127
|
-
res = self._api.get_rotated_secret_value(self.
|
|
277
|
+
res: dict[str, str] = self._api.get_rotated_secret_value(self.akeyless.GetRotatedSecretValue(**kwargs))["value"] # type: ignore
|
|
278
|
+
if json_attribute:
|
|
279
|
+
return get_nested_attribute(res, json_attribute)
|
|
128
280
|
return res
|
|
129
281
|
|
|
130
|
-
def
|
|
131
|
-
|
|
132
|
-
|
|
282
|
+
def describe_secret(self, path: str) -> Any:
|
|
283
|
+
"""
|
|
284
|
+
Get metadata about a secret.
|
|
285
|
+
|
|
286
|
+
Checks permissions before retrieving metadata and raises PermissionsError if the user
|
|
287
|
+
doesn't have read permission for the path.
|
|
288
|
+
"""
|
|
289
|
+
if not "read" in self.describe_permissions(path):
|
|
290
|
+
raise PermissionsError(f"You do not have permission the secret '{path}'")
|
|
291
|
+
|
|
292
|
+
return self.api.describe_item(self.akeyless.DescribeItem(name=path, token=self._get_token()))
|
|
293
|
+
|
|
294
|
+
def list_secrets(self, path: str) -> list[Any]:
|
|
295
|
+
"""
|
|
296
|
+
List all secrets at the given path.
|
|
297
|
+
|
|
298
|
+
Checks permissions before listing secrets and raises PermissionsError if the user doesn't
|
|
299
|
+
have list permission for the path. Returns an empty list if no secrets are found.
|
|
300
|
+
"""
|
|
301
|
+
if not "list" in self.describe_permissions(path):
|
|
302
|
+
raise PermissionsError(f"You do not have permission the secrets in '{path}'")
|
|
303
|
+
|
|
304
|
+
res: ListItemsOutput = self.api.list_items( # type: ignore
|
|
305
|
+
self.akeyless.ListItems(
|
|
306
|
+
path=path,
|
|
307
|
+
token=self._get_token(),
|
|
308
|
+
)
|
|
309
|
+
)
|
|
133
310
|
if not res.items:
|
|
134
311
|
return []
|
|
135
312
|
|
|
136
313
|
return [item.item_name for item in res.items]
|
|
137
314
|
|
|
138
|
-
def update(self, path, value):
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
315
|
+
def update(self, path: str, value: Any) -> None:
|
|
316
|
+
"""
|
|
317
|
+
Update an existing secret.
|
|
318
|
+
|
|
319
|
+
Checks permissions before updating the secret and raises PermissionsError if the user
|
|
320
|
+
doesn't have write permission for the path. The value is converted to a string before storage.
|
|
321
|
+
"""
|
|
322
|
+
if not "write" in self.describe_permissions(path):
|
|
323
|
+
raise PermissionsError(f"You do not have permission the secret '{path}'")
|
|
324
|
+
|
|
325
|
+
res = self.api.update_secret_val(
|
|
326
|
+
self.akeyless.UpdateSecretVal(name=path, value=str(value), token=self._get_token())
|
|
142
327
|
)
|
|
143
|
-
return True
|
|
144
328
|
|
|
145
|
-
def upsert(self, path, value):
|
|
329
|
+
def upsert(self, path: str, value: Any) -> None:
|
|
330
|
+
"""
|
|
331
|
+
Create or update a secret.
|
|
332
|
+
|
|
333
|
+
This method attempts to update an existing secret, and if that fails, it tries to create
|
|
334
|
+
a new one. The value is converted to a string before storage.
|
|
335
|
+
"""
|
|
146
336
|
try:
|
|
147
|
-
|
|
148
|
-
return True
|
|
337
|
+
self.update(path, value)
|
|
149
338
|
except Exception as e:
|
|
150
|
-
|
|
339
|
+
self.create(path, value)
|
|
151
340
|
|
|
152
341
|
def list_sub_folders(self, main_folder: str) -> list[str]:
|
|
153
|
-
"""
|
|
154
|
-
|
|
342
|
+
"""
|
|
343
|
+
Return the list of secrets/sub folders in the given folder.
|
|
344
|
+
|
|
345
|
+
Checks permissions before listing subfolders and raises PermissionsError if the user doesn't
|
|
346
|
+
have list permission for the path. Returns the relative subfolder names without the parent path.
|
|
347
|
+
"""
|
|
348
|
+
if not "list" in self.describe_permissions(main_folder):
|
|
349
|
+
raise PermissionsError(f"You do not have permission to list sub folders in '{main_folder}'")
|
|
350
|
+
|
|
351
|
+
items = self.api.list_items(self.akeyless.ListItems(path=main_folder, token=self._get_token()))
|
|
155
352
|
|
|
156
353
|
# akeyless will return the absolute path and end in a slash but we only want the folder name
|
|
157
354
|
main_folder_string_len = len(main_folder)
|
|
158
|
-
return [sub_folder[main_folder_string_len:-1] for sub_folder in items.folders]
|
|
355
|
+
return [sub_folder[main_folder_string_len:-1] for sub_folder in items.folders] # type: ignore
|
|
159
356
|
|
|
160
|
-
def get_ssh_certificate(self, cert_issuer, cert_username, path_to_public_file):
|
|
161
|
-
|
|
357
|
+
def get_ssh_certificate(self, cert_issuer: str, cert_username: str, path_to_public_file: str) -> Any:
|
|
358
|
+
"""
|
|
359
|
+
Get an SSH certificate from Akeyless.
|
|
162
360
|
|
|
361
|
+
Reads the public key from the specified file path and requests a certificate for the given
|
|
362
|
+
username and issuer from Akeyless.
|
|
363
|
+
"""
|
|
163
364
|
with open(path_to_public_file, "r") as fp:
|
|
164
365
|
public_key = fp.read()
|
|
165
366
|
|
|
166
|
-
res = self.
|
|
167
|
-
self.
|
|
367
|
+
res = self.api.get_ssh_certificate(
|
|
368
|
+
self.akeyless.GetSSHCertificate(
|
|
168
369
|
cert_username=cert_username,
|
|
169
370
|
cert_issuer_name=cert_issuer,
|
|
170
371
|
public_key_data=public_key,
|
|
@@ -172,70 +373,135 @@ class AKeyless:
|
|
|
172
373
|
)
|
|
173
374
|
)
|
|
174
375
|
|
|
175
|
-
return res.data
|
|
376
|
+
return res.data # type: ignore
|
|
176
377
|
|
|
177
|
-
def
|
|
178
|
-
|
|
179
|
-
|
|
378
|
+
def _get_token(self) -> str:
|
|
379
|
+
"""
|
|
380
|
+
Get an authentication token for Akeyless API calls.
|
|
180
381
|
|
|
181
|
-
|
|
382
|
+
Returns a cached token if available and not expired (within 10 seconds), otherwise obtains
|
|
383
|
+
a new one using the configured authentication method. Tokens are valid for about an hour,
|
|
384
|
+
but we set the refresh time to 30 minutes to be safe.
|
|
385
|
+
"""
|
|
182
386
|
# AKeyless tokens live for an hour
|
|
183
|
-
if
|
|
387
|
+
if (
|
|
388
|
+
hasattr(self, "_token_refresh")
|
|
389
|
+
and hasattr(self, "_token")
|
|
390
|
+
and (self._token_refresh - datetime.datetime.now()).total_seconds() > 10
|
|
391
|
+
):
|
|
184
392
|
return self._token
|
|
185
393
|
|
|
186
|
-
auth_method_name = f"auth_{self.
|
|
394
|
+
auth_method_name = f"auth_{self.access_type}"
|
|
187
395
|
if not hasattr(self, auth_method_name):
|
|
188
|
-
raise ValueError(f"Requested
|
|
396
|
+
raise ValueError(f"Requested Akeyless authentication with unsupported auth method: '{self.access_type}'")
|
|
189
397
|
|
|
190
398
|
self._token_refresh = datetime.datetime.now() + datetime.timedelta(hours=0.5)
|
|
191
399
|
self._token = getattr(self, auth_method_name)()
|
|
192
400
|
return self._token
|
|
193
401
|
|
|
194
402
|
def auth_aws_iam(self):
|
|
195
|
-
|
|
403
|
+
"""
|
|
404
|
+
Authenticate using AWS IAM.
|
|
405
|
+
|
|
406
|
+
Uses the akeyless_cloud_id package to generate a cloud ID and authenticates with Akeyless
|
|
407
|
+
using the configured access_id.
|
|
408
|
+
"""
|
|
409
|
+
from akeyless_cloud_id import CloudId # type: ignore
|
|
196
410
|
|
|
197
|
-
res = self.
|
|
198
|
-
self.
|
|
411
|
+
res = self.api.auth(
|
|
412
|
+
self.akeyless.Auth(access_id=self.access_id, access_type="aws_iam", cloud_id=CloudId().generate())
|
|
199
413
|
)
|
|
200
|
-
return res.token
|
|
414
|
+
return res.token # type: ignore
|
|
201
415
|
|
|
202
416
|
def auth_saml(self):
|
|
417
|
+
"""
|
|
418
|
+
Authenticate using SAML.
|
|
419
|
+
|
|
420
|
+
Uses the akeyless CLI to generate credentials and then retrieves a token either directly
|
|
421
|
+
from the credentials file or by making an API call to convert the credentials to a token.
|
|
422
|
+
"""
|
|
423
|
+
import json
|
|
203
424
|
import os
|
|
204
425
|
from pathlib import Path
|
|
205
426
|
|
|
206
|
-
os.system(f"akeyless list-items --profile {self.
|
|
427
|
+
os.system(f"akeyless list-items --profile {self.profile} --path /not/a/real/path > /dev/null 2>&1")
|
|
207
428
|
home = str(Path.home())
|
|
208
|
-
with open(f"{home}/.akeyless/.tmp_creds/{self.
|
|
429
|
+
with open(f"{home}/.akeyless/.tmp_creds/{self.profile}-{self.access_id}", "r") as creds_file:
|
|
209
430
|
credentials = creds_file.read()
|
|
210
|
-
|
|
431
|
+
credentials_json = json.loads(credentials)
|
|
432
|
+
if "token" in credentials_json:
|
|
433
|
+
return credentials_json["token"]
|
|
211
434
|
# and now we can turn that into a token
|
|
212
|
-
response = self.
|
|
435
|
+
response = self.requests.post(
|
|
213
436
|
"https://rest.akeyless.io/",
|
|
214
437
|
data={
|
|
215
438
|
"cmd": "static-creds-auth",
|
|
216
|
-
"access-id": self.
|
|
439
|
+
"access-id": self.access_id,
|
|
217
440
|
"creds": credentials.strip(),
|
|
218
441
|
},
|
|
219
442
|
)
|
|
220
443
|
return response.json()["token"]
|
|
221
444
|
|
|
222
445
|
def auth_jwt(self):
|
|
223
|
-
|
|
446
|
+
"""
|
|
447
|
+
Authenticate using JWT.
|
|
448
|
+
|
|
449
|
+
Retrieves the JWT from the environment variable specified by jwt_env_key and authenticates
|
|
450
|
+
with Akeyless. Raises ValueError if jwt_env_key is not specified.
|
|
451
|
+
"""
|
|
452
|
+
if not self.jwt_env_key:
|
|
224
453
|
raise ValueError(
|
|
225
|
-
"To use AKeyless JWT Auth,
|
|
226
|
-
|
|
227
|
-
res = self._api.auth(
|
|
228
|
-
self._akeyless.Auth(
|
|
229
|
-
access_id=self._access_id, access_type="jwt", jwt=self._environment.get(self._jwt_env_key)
|
|
454
|
+
"To use AKeyless JWT Auth, "
|
|
455
|
+
"you must specify the name of the ENV key to load the JWT from when configuring AKeyless"
|
|
230
456
|
)
|
|
457
|
+
res = self.api.auth(
|
|
458
|
+
self.akeyless.Auth(access_id=self.access_id, access_type="jwt", jwt=self.environment.get(self.jwt_env_key))
|
|
231
459
|
)
|
|
232
|
-
return res.token
|
|
460
|
+
return res.token # type: ignore
|
|
233
461
|
|
|
234
|
-
def
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return
|
|
462
|
+
def describe_permissions(self, path: str, type: str = "item") -> list[str]:
|
|
463
|
+
"""
|
|
464
|
+
List permissions for a path.
|
|
465
|
+
|
|
466
|
+
Returns a list of permission strings (e.g., "read", "write", "list") that the current
|
|
467
|
+
authentication token has for the specified path.
|
|
468
|
+
"""
|
|
469
|
+
return self.api.describe_permissions(
|
|
470
|
+
self.akeyless.DescribePermissions(token=self._get_token(), path=path, type=type)
|
|
471
|
+
).client_permissions # type: ignore
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
class AkeylessSaml(Akeyless):
|
|
475
|
+
"""Convenience class for SAML authentication with Akeyless."""
|
|
476
|
+
|
|
477
|
+
def __init__(self, access_id: str, api_host: str = "", profile: str = ""):
|
|
478
|
+
"""
|
|
479
|
+
Initialize with SAML authentication.
|
|
480
|
+
|
|
481
|
+
Sets access_type to "saml" and passes the remaining parameters to the parent class.
|
|
482
|
+
"""
|
|
483
|
+
return super().__init__(access_id, "saml", api_host=api_host, profile=profile)
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
class AkeylessJwt(Akeyless):
|
|
487
|
+
"""Convenience class for JWT authentication with Akeyless."""
|
|
488
|
+
|
|
489
|
+
def __init__(self, access_id: str, jwt_env_key: str = "", api_host: str = "", profile: str = ""):
|
|
490
|
+
"""
|
|
491
|
+
Initialize with JWT authentication.
|
|
492
|
+
|
|
493
|
+
Sets access_type to "jwt" and passes the remaining parameters to the parent class.
|
|
494
|
+
"""
|
|
495
|
+
return super().__init__(access_id, "jwt", jwt_env_key=jwt_env_key, api_host=api_host, profile=profile)
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class AkeylessAwsIam(Akeyless):
|
|
499
|
+
"""Convenience class for AWS IAM authentication with Akeyless."""
|
|
500
|
+
|
|
501
|
+
def __init__(self, access_id: str, api_host: str = ""):
|
|
502
|
+
"""
|
|
503
|
+
Initialize with AWS IAM authentication.
|
|
504
|
+
|
|
505
|
+
Sets access_type to "aws_iam" and passes the remaining parameters to the parent class.
|
|
506
|
+
"""
|
|
507
|
+
return super().__init__(access_id, "aws_iam", api_host=api_host)
|