Merge pull request #45 from nicoangelo/feature/attachments
This commit is contained in:
commit
fc37a12737
16
README.md
16
README.md
@ -129,7 +129,7 @@ type: dockerconfigjson
|
|||||||
|
|
||||||
## BitwardenTemplate
|
## BitwardenTemplate
|
||||||
|
|
||||||
One of the more freely defined types that can be used with this operator you can just pass a whole template:
|
One of the more freely defined types that can be used with this operator you can just pass a whole template. Also the lookup function `bitwarden_lookup` is available to reference parts of the secret:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
---
|
---
|
||||||
@ -145,11 +145,11 @@ spec:
|
|||||||
---
|
---
|
||||||
api:
|
api:
|
||||||
enabled: True
|
enabled: True
|
||||||
key: {{ bitwarden_lookup("A Secret ID from bitwarden", "login or fields", "name of a field in bitwarden") }}
|
key: {{ bitwarden_lookup("A Secret ID from bitwarden", "login or fields or attachment", "name of a field in bitwarden") }}
|
||||||
allowCrossOrigin: false
|
allowCrossOrigin: false
|
||||||
apps:
|
apps:
|
||||||
"some.app.identifier:some_version":
|
"some.app.identifier:some_version":
|
||||||
pubkey: {{ bitwarden_lookup("A Secret ID from bitwarden", "login or fields", "name of a field in bitwarden") }}
|
pubkey: {{ bitwarden_lookup("A Secret ID from bitwarden", "login or fields or attachment", "name of a field in bitwarden") }}
|
||||||
enabled: true
|
enabled: true
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -169,7 +169,15 @@ metadata:
|
|||||||
type: Opaque
|
type: Opaque
|
||||||
```
|
```
|
||||||
|
|
||||||
please note that the rendering engine for this template is jinja2, with an addition of a custom `bitwarden_lookup` function, so there are more possibilities to inject here.
|
The signature of `bitwarden_lookup` is `(item_id, scope, field)`:
|
||||||
|
- `item_id`: The item ID of the secret in Bitwarden
|
||||||
|
- `scope`: one of `login`, `fields` or `attachment`
|
||||||
|
- `field`:
|
||||||
|
- when `scope` is `login`: either `username` or `password`
|
||||||
|
- when `scope` is `fields`: the name of a custom field
|
||||||
|
- when `scope` is `attachment`: the filename of a file attached to the item
|
||||||
|
|
||||||
|
Please note that the rendering engine for this template is jinja2, with an addition of a custom `bitwarden_lookup` function, so there are more possibilities to inject here.
|
||||||
|
|
||||||
## Configurations parameters
|
## Configurations parameters
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ description: Deploy the Bitwarden CRD Operator
|
|||||||
|
|
||||||
type: application
|
type: application
|
||||||
|
|
||||||
version: "v0.9.0"
|
version: "v0.10.0"
|
||||||
|
|
||||||
appVersion: "0.8.0"
|
appVersion: "0.9.0"
|
||||||
|
|
||||||
keywords:
|
keywords:
|
||||||
- operator
|
- operator
|
||||||
@ -89,18 +89,14 @@ annotations:
|
|||||||
allowCrossOrigin: false
|
allowCrossOrigin: false
|
||||||
apps:
|
apps:
|
||||||
"some.app.identifier:some_version":
|
"some.app.identifier:some_version":
|
||||||
pubkey: {{ bitwarden_lookup("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "fields", "public_key") }}
|
pubkey: {{ bitwarden_lookup("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "attachment", "public_key") }}
|
||||||
enabled: true
|
enabled: true
|
||||||
artifacthub.io/license: MIT
|
artifacthub.io/license: MIT
|
||||||
artifacthub.io/operator: "true"
|
artifacthub.io/operator: "true"
|
||||||
artifacthub.io/containsSecurityUpdates: "false"
|
artifacthub.io/containsSecurityUpdates: "false"
|
||||||
artifacthub.io/changes: |
|
artifacthub.io/changes: |
|
||||||
- kind: changed
|
|
||||||
description: "Unified scheduled none crd related operations (bw sync and login)"
|
|
||||||
- kind: added
|
- kind: added
|
||||||
description: "Added relogin interval which can be finetuned with env `BW_RELOGIN_INTERVAL`. defaults to 3600 seconds"
|
description: "Added attachment lookup to bitwarden_lookup in BitwardenTemplate CRD"
|
||||||
- kind: chanced
|
|
||||||
description: "Updated python to 3.11.6-r0"
|
|
||||||
artifacthub.io/images: |
|
artifacthub.io/images: |
|
||||||
- name: bitwarden-crd-operator
|
- name: bitwarden-crd-operator
|
||||||
image: ghcr.io/lerentis/bitwarden-crd-operator:0.8.0
|
image: ghcr.io/lerentis/bitwarden-crd-operator:0.9.0
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import json
|
from utils.utils import get_secret_from_bitwarden, get_attachment, parse_fields_scope, parse_login_scope
|
||||||
|
|
||||||
from utils.utils import get_secret_from_bitwarden, parse_fields_scope, parse_login_scope
|
|
||||||
|
|
||||||
|
|
||||||
def bitwarden_lookup(id, scope, field):
|
class BitwardenLookupHandler:
|
||||||
_secret_json = get_secret_from_bitwarden(None, id)
|
|
||||||
if scope == "login":
|
def __init__(self, logger) -> None:
|
||||||
return parse_login_scope(_secret_json, field)
|
self.logger = logger
|
||||||
if scope == "fields":
|
|
||||||
return parse_fields_scope(_secret_json, field)
|
def bitwarden_lookup(self, id, scope, field):
|
||||||
|
if scope == "attachment":
|
||||||
|
return get_attachment(self.logger, id, field)
|
||||||
|
_secret_json = get_secret_from_bitwarden(self.logger, id)
|
||||||
|
if scope == "login":
|
||||||
|
return parse_login_scope(_secret_json, field)
|
||||||
|
if scope == "fields":
|
||||||
|
return parse_fields_scope(_secret_json, field)
|
||||||
|
@ -4,27 +4,24 @@ import kubernetes
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from utils.utils import unlock_bw, bw_sync_interval
|
from utils.utils import unlock_bw, bw_sync_interval
|
||||||
from lookups.bitwarden_lookup import bitwarden_lookup
|
from lookups.bitwarden_lookup import BitwardenLookupHandler
|
||||||
from jinja2 import Environment, BaseLoader
|
from jinja2 import Environment, BaseLoader
|
||||||
|
|
||||||
|
|
||||||
lookup_func_dict = {
|
def render_template(logger, template):
|
||||||
"bitwarden_lookup": bitwarden_lookup,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def render_template(template):
|
|
||||||
jinja_template = Environment(loader=BaseLoader()).from_string(template)
|
jinja_template = Environment(loader=BaseLoader()).from_string(template)
|
||||||
jinja_template.globals.update(lookup_func_dict)
|
jinja_template.globals.update({
|
||||||
|
"bitwarden_lookup": BitwardenLookupHandler(logger).bitwarden_lookup,
|
||||||
|
})
|
||||||
return jinja_template.render()
|
return jinja_template.render()
|
||||||
|
|
||||||
|
|
||||||
def create_template_secret(secret, filename, template):
|
def create_template_secret(logger, secret, filename, template):
|
||||||
secret.type = "Opaque"
|
secret.type = "Opaque"
|
||||||
secret.data = {}
|
secret.data = {}
|
||||||
secret.data[filename] = str(
|
secret.data[filename] = str(
|
||||||
base64.b64encode(
|
base64.b64encode(
|
||||||
render_template(template).encode("utf-8")),
|
render_template(logger, template).encode("utf-8")),
|
||||||
"utf-8")
|
"utf-8")
|
||||||
return secret
|
return secret
|
||||||
|
|
||||||
@ -48,7 +45,7 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs):
|
|||||||
secret = kubernetes.client.V1Secret()
|
secret = kubernetes.client.V1Secret()
|
||||||
secret.metadata = kubernetes.client.V1ObjectMeta(
|
secret.metadata = kubernetes.client.V1ObjectMeta(
|
||||||
name=secret_name, annotations=annotations)
|
name=secret_name, annotations=annotations)
|
||||||
secret = create_template_secret(secret, filename, template)
|
secret = create_template_secret(logger, secret, filename, template)
|
||||||
|
|
||||||
obj = api.create_namespaced_secret(
|
obj = api.create_namespaced_secret(
|
||||||
secret_namespace, secret
|
secret_namespace, secret
|
||||||
@ -109,7 +106,7 @@ def update_managed_secret(
|
|||||||
secret = kubernetes.client.V1Secret()
|
secret = kubernetes.client.V1Secret()
|
||||||
secret.metadata = kubernetes.client.V1ObjectMeta(
|
secret.metadata = kubernetes.client.V1ObjectMeta(
|
||||||
name=secret_name, annotations=annotations)
|
name=secret_name, annotations=annotations)
|
||||||
secret = create_template_secret(secret, filename, template)
|
secret = create_template_secret(logger, secret, filename, template)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = api.replace_namespaced_secret(
|
obj = api.replace_namespaced_secret(
|
||||||
|
@ -39,6 +39,10 @@ def sync_bw(logger, force=False):
|
|||||||
logger.info(f"Sync successful {status_output}")
|
logger.info(f"Sync successful {status_output}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_attachment(logger, id, name):
|
||||||
|
return command_wrapper(logger, command=f"get attachment {name} --itemid {id}", raw=True)
|
||||||
|
|
||||||
|
|
||||||
def unlock_bw(logger):
|
def unlock_bw(logger):
|
||||||
status_output = command_wrapper(logger, "status", False)
|
status_output = command_wrapper(logger, "status", False)
|
||||||
status = status_output['data']['template']['status']
|
status = status_output['data']['template']['status']
|
||||||
@ -50,17 +54,22 @@ def unlock_bw(logger):
|
|||||||
logger.info("Signin successful. Session exported")
|
logger.info("Signin successful. Session exported")
|
||||||
|
|
||||||
|
|
||||||
def command_wrapper(logger, command, use_success: bool = True):
|
def command_wrapper(logger, command, use_success: bool = True, raw: bool = False):
|
||||||
system_env = dict(os.environ)
|
system_env = dict(os.environ)
|
||||||
|
response_flag = "--raw" if raw else "--response"
|
||||||
sp = subprocess.Popen(
|
sp = subprocess.Popen(
|
||||||
[f"bw --response {command}"],
|
[f"bw {response_flag} {command}"],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
close_fds=True,
|
close_fds=True,
|
||||||
shell=True,
|
shell=True,
|
||||||
env=system_env)
|
env=system_env)
|
||||||
out, err = sp.communicate()
|
out, err = sp.communicate()
|
||||||
|
if err:
|
||||||
|
logger.warn(err)
|
||||||
|
return None
|
||||||
|
if raw:
|
||||||
|
return out.decode(encoding='UTF-8')
|
||||||
if "DEBUG" in system_env:
|
if "DEBUG" in system_env:
|
||||||
logger.info(out.decode(encoding='UTF-8'))
|
logger.info(out.decode(encoding='UTF-8'))
|
||||||
resp = json.loads(out.decode(encoding='UTF-8'))
|
resp = json.loads(out.decode(encoding='UTF-8'))
|
||||||
|
Loading…
Reference in New Issue
Block a user