Skip to content

Commit aded910

Browse files
committed
fix: updated secret entry getter, updated README
1 parent 9a2c948 commit aded910

5 files changed

Lines changed: 159 additions & 11 deletions

File tree

‎README.md‎

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,145 @@
1-
# python-yc-lockbox
2-
Client for Yandex.Cloud Lockbox (secrets vault)
1+
# Yandex Lockbox Client
2+
3+
This client is a simple library for working with **[Yandex Lockbox](https://cloud.yandex.ru/en/docs/lockbox/)** over REST API, simplifying work with secrets and allowing you to work with them in the OOP paradigm.
4+
5+
6+
**Currently, the following operations are not supported by the library:**
7+
8+
* List secret access bindings
9+
* Set secret access bindings
10+
* Update secret access bindings
11+
* List secret operations
12+
13+
14+
15+
## Install
16+
17+
Installing with PIP:
18+
19+
```
20+
pip3 install yc-lockbox
21+
```
22+
23+
Also, you can install from source with:
24+
25+
```
26+
git clone https://github.com/akimrx/python-yc-lockbox
27+
cd python-yc-lockbox
28+
make install
29+
```
30+
31+
32+
## Usage
33+
34+
35+
* **Authenticate via your [OAuth token](https://oauth.yandex.com/authorize?response_type=token&client_id=1a6990aa636648e9b2ef855fa7bec2fb)**
36+
37+
```python
38+
from yc_lockbox import YandexLockboxClient
39+
40+
lockbox = YandexLockboxClient("y0_xxxxxxxxxxxx")
41+
```
42+
43+
* **Authenticate via [IAM token](https://cloud.yandex.com/en/docs/iam/operations/iam-token/create)**
44+
45+
> If you pass a IAM token as credentials, you need to take care of the freshness of the token yourself.
46+
47+
```python
48+
from yc_lockbox import YandexLockboxClient
49+
50+
lockbox = YandexLockboxClient("t1.xxxxxx.xxxxxxx")
51+
```
52+
53+
54+
55+
* **Authenticate using [service account key](https://cloud.yandex.com/en/docs/iam/operations/authorized-key/create#cli_1)**
56+
57+
```python
58+
import json
59+
from yc_lockbox import YandexLockboxClient
60+
61+
with open("/path/to/key.json", "r") as keyfile:
62+
credentials = keyfile.read()
63+
64+
lockbox = YandexLockboxClient(credentials)
65+
```
66+
67+
### Create a new secret
68+
69+
```python
70+
from yc_lockbox import YandexLockboxClient, INewSecret, INewSecretPayloadEntry
71+
72+
lockbox = YandexLockboxClient("oauth_or_iam_token")
73+
74+
my_secret = lockbox.create_secret(
75+
INewSecret(
76+
folder_id="b1xxxxxxxxxxxxxx",
77+
name="my-secret",
78+
version_payload_entries=[
79+
INewSecretPayloadEntry(key="secret_entry_1", text_value="secret_entry_text_value"),
80+
INewSecretPayloadEntry(key="secret_entry_2", binary_value="secret_entry_binary_value"),
81+
],
82+
)
83+
)
84+
85+
if my_secret.done:
86+
print(my_secret.metadata.get("secretId"))
87+
```
88+
89+
90+
### Get secret from Lockbox
91+
92+
```python
93+
from yc_lockbox import YandexLockboxClient, Secret
94+
95+
lockbox = YandexLockboxClient("oauth_or_iam_token")
96+
97+
secret: Secret = lockbox.get_secret("e6qxxxxxxxxxx")
98+
print(secret.status, secret.name)
99+
100+
payload = secret.payload(version_id=secret.current_version.id) # version_id is optional, by default using current version
101+
entry = payload["secret_entry_1"] # or payload.get("secret_entry_1")
102+
103+
print(entry.text_value) # return MASKED value like ***********
104+
print(entry.reveal_text_value()) # similar to entry.text_value.get_secret_value()
105+
```
106+
107+
108+
### Add new version of secret
109+
110+
```python
111+
from yc_lockbox import YandexLockboxClient, Secret, INewSecretVersion
112+
113+
lockbox = YandexLockboxClient("oauth_or_iam_token")
114+
115+
secret: Secret = lockbox.get_secret("e6qxxxxxxxxxxxx")
116+
117+
secret.add_version([
118+
INewSecretPayloadEntry(key="secret_entry_1", text_value="secret_entry_text_value"),
119+
INewSecretPayloadEntry(key="secret_entry_2", binary_value="secret_entry_binary_value"),
120+
])
121+
122+
# alternative
123+
lockbox.add_secret_version("secret_id", version=[INewSecretPayloadEntry(...), INewSecretPayloadEntry(...)])
124+
125+
```
126+
127+
128+
### Other operations with secret
129+
130+
```python
131+
from yc_lockbox import YandexLockboxClient
132+
133+
lockbox = YandexLockboxClient("oauth_or_iam_token")
134+
135+
136+
for secret in lockbox.list_secrets(folder_id="b1xxxxxxxxxx", iterator=True):
137+
print(secret.deactivate())
138+
print(secret.activate())
139+
140+
for version in secret.list_versions(iterator=True):
141+
if version.id != secret.current_version.id:
142+
print(version.schedule_version_destruction())
143+
print(version.cancel_version_destruction())
144+
145+
```

‎examples/async_example.py‎

Whitespace-only changes.

‎examples/sync_example.py‎

Whitespace-only changes.

‎yc_lockbox/_lockbox.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def __init__(
7575
credentials,
7676
*,
7777
auth_client: Optional[Type[AbstractYandexAuthClient]] = YandexAuthClient,
78-
adapter: AbstractHTTPAdapter = HTTPAdapter,
78+
adapter: Optional[Type[AbstractHTTPAdapter]] = HTTPAdapter,
7979
lockbox_base_url: str | None = None,
8080
payload_lockbox_base_url: str | None = None,
8181
) -> None:

‎yc_lockbox/_models.py‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,20 +108,25 @@ class SecretPayload(BaseDomainModel):
108108
version_id: str = Field(..., alias="versionId")
109109
entries: list[SecretPayloadEntry]
110110

111-
def get_entry(self, key: str) -> SecretPayloadEntry | None:
111+
def __getitem__(self, key: str) -> SecretPayloadEntry | None:
112+
"""Get entry by key. Dictionary like."""
113+
value: SecretPayloadEntry | None = self.get(key, default=None)
114+
115+
if value is None:
116+
entries = ", ".join(map(lambda entry: entry.key, self.entries))
117+
raise KeyError(f"Entry with name {key} not exists. Available entries: {entries}")
118+
119+
return value
120+
121+
def get(self, key: str, default: Any = None) -> SecretPayloadEntry | None:
112122
"""
113123
Get entry object from payload.
114124
115125
:param key: Entry key (name).
126+
:param default: Default return value if key not exists.
116127
:raises KeyError: When key not exists in payload.
117128
"""
118-
found = next(filter(lambda entry: entry.key == key, self.entries), None)
119-
120-
if found is None:
121-
entries = ", ".join(map(lambda entry: entry.key, self.entries))
122-
raise KeyError(f"Entry with name {key} not exists. Available entries: {entries}")
123-
124-
return found
129+
return next(filter(lambda entry: entry.key == key, self.entries), default)
125130

126131

127132
class SecretVersion(BaseDomainModel):

0 commit comments

Comments
 (0)