Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement: Add token based auth as alternative to basic-auth for http requests. #192

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.iml
.idea/
venv
.vscode/
__pycache__
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ metadata:
k8s-sidecar-target-directory: "/path/to/target/directory"
```

If the filename ends with `.url` suffix, the content will be processed as a URL which the target file contents will be downloaded from.
If the filename ends with `.url` suffix, the content will be processed as a URL which the target file contents will be downloaded from. If the source requires authentication, currently http basic-auth and token based authentication via query param are supported. Please see the variables below for details.

## Configuration Environment Variables

Expand All @@ -69,6 +69,8 @@ If the filename ends with `.url` suffix, the content will be processed as a URL
| `REQ_RETRY_READ` | How many times to retry on read errors for any http request (`.url` triggered requests, requests to `REQ_URI` and k8s api requests) | false | `5` | integer |
| `REQ_RETRY_BACKOFF_FACTOR` | A backoff factor to apply between attempts after the second try for any http request (`.url` triggered requests, requests to `REQ_URI` and k8s api requests) | false | `1.1` | float |
| `REQ_TIMEOUT` | How many seconds to wait for the server to send data before giving up for `.url` triggered requests or requests to `REQ_URI` (does not apply to k8s api requests) | false | `10` | float |
| `REQ_TOKEN_KEY` | Key of the key/value pair passed as parameter within the url for token based authentication for requests to `REQ_URL` and for `*.url` triggered requests. If `REQ_TOKEN_VALUE` is set and `REQ_TOKEN_KEY` is not, it defaults to "`private_token`". | false | - | string |
| `REQ_TOKEN_VALUE` | Value of the key/value pair passed as parameter within the url for token based authentication for requests to `REQ_URL` and for `*.url` triggered requests. If configured it takes precedence over eventually also configured basic-auth credentials (`REQ_USERNAME`/`REQ_PASSWORD`) | false | - | string |
| `REQ_USERNAME` | Username to use for basic authentication for requests to `REQ_URL` and for `*.url` triggered requests | false | - | string |
| `REQ_PASSWORD` | Password to use for basic authentication for requests to `REQ_URL` and for `*.url` triggered requests | false | - | string |
| `SCRIPT` | Absolute path to shell script to execute after a configmap got reloaded. It runs before calls to `REQ_URI` | false | - | string |
Expand Down
16 changes: 16 additions & 0 deletions example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ spec:
volumeMounts:
- name: shared-volume
mountPath: /tmp/
# Only relevant for token based auth (like with git)
# envFrom:
# - secretRef:
# name: token-auth-sample-secret
env:
- name: LABEL
value: "findme"
Expand Down Expand Up @@ -71,6 +75,18 @@ data:
# base64 encoded: my super cool \n multiline \ secret
secret.world: bXkgc3VwZXIgY29vbAptdWx0aWxpbmUKc2VjcmV0
---
# This secret is only necessary for token based authentication of http requests.
# Refer to README.md for details on the two parameters REQ_TOKEN_KEY and REQ_TOKEN_VALUE
apiVersion: v1
kind: Secret
metadata:
name: token-auth-sample-secret
type: Opaque
data:
#REQ_TOKEN_KEY: private_token
# base64 encoded super-duper-secret authentication token
REQ_TOKEN_VALUE: c3VwZXItZHVwZXItc2VjcmV0
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
Expand Down
29 changes: 26 additions & 3 deletions src/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,33 @@ def request(url, method, enable_5xx=False, payload=None):

username = os.getenv("REQ_USERNAME")
password = os.getenv("REQ_PASSWORD")
if username and password:
req_token_key = os.getenv("REQ_TOKEN_KEY")
req_token_value = os.getenv("REQ_TOKEN_VALUE")
params=dict()

if req_token_value and not req_token_key:
req_token_key = "private_token"
logger.info(f"Request token value is set, but key is not. Setting request token key to default value {req_token_key}.")
jekkel marked this conversation as resolved.
Show resolved Hide resolved

if req_token_key and req_token_value:
auth = None
params[ str(req_token_key) ] = req_token_value
logger.info(f"Token based authorization configured. Token key: {req_token_key}.")
jekkel marked this conversation as resolved.
Show resolved Hide resolved
logger.debug(f"Token value {params[str(req_token_key)]}.")
jekkel marked this conversation as resolved.
Show resolved Hide resolved
elif username and password:
auth = (username, password)
params = None
logger.info(f"Basic-auth configured. username: {username}.")
jekkel marked this conversation as resolved.
Show resolved Hide resolved
logger.debug(f"Basic-auth configured. password: {password}.")
jekkel marked this conversation as resolved.
Show resolved Hide resolved
else:
logger.info(f"No authorization tokens set (no basic-auth and no private token).")
jekkel marked this conversation as resolved.
Show resolved Hide resolved
auth = None
params = None

if params:
logger.debug(f"Request params are set as follows: {params}")
else:
logger.info(f"No request params are set.")
jekkel marked this conversation as resolved.
Show resolved Hide resolved

r = requests.Session()

Expand All @@ -123,9 +146,9 @@ def request(url, method, enable_5xx=False, payload=None):

# If method is not provided use GET as default
if method == "GET" or not method:
res = r.get("%s" % url, auth=auth, timeout=REQ_TIMEOUT)
res = r.get("%s" % url, auth=auth, params=params, timeout=REQ_TIMEOUT)
elif method == "POST":
res = r.post("%s" % url, auth=auth, json=payload, timeout=REQ_TIMEOUT)
res = r.post("%s" % url, auth=auth, params=params, json=payload, timeout=REQ_TIMEOUT)
else:
logger.warning(f"Invalid REQ_METHOD: '{method}', please use 'GET' or 'POST'. Doing nothing.")
return
Expand Down