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

feat(secretstores): Add Docker Secrets #13035

Merged
merged 16 commits into from
Apr 25, 2023
Merged

Conversation

shantanoo-desai
Copy link
Contributor

@shantanoo-desai shantanoo-desai commented Apr 4, 2023

This feature adds the secret-store for Docker Secrets to Telegraf. This PR is a resultant effort based on discussion for a feature-request in #12848.

In a nutshell, Docker can inject secrets to a container during boot into files under /run/secrets/<secret_file_x> depending on the configuration mentioned within a docker-compose.yml file. This plugin uses these _injected_f files to read credentials and passes them to the respective resolver strings wherever they are mentioned in plugins.

Changes

Following files are introduced with this PR, which complies with other secret-store plugins file structure:

  • plugins/secretstores/all/docker.go
  • plugins/secretstores/docker/docker.go
  • plugins/secretstores/docker/docker_test.go
  • plugins/secretstores/docker/README.md
  • plugins/secretstores/docker/sample.conf

Required for all PRs

resolves #12848

This feature adds the secret-store for Docker Secrets to Telegraf.
This PR is a resultant effort based on discussion for a feature-request
 in influxdata#12848. Upon acceptance this PR closes influxdata#12848

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
@telegraf-tiger
Copy link
Contributor

telegraf-tiger bot commented Apr 4, 2023

Thanks so much for the pull request!
🤝 ✒️ Just a reminder that the CLA has not yet been signed, and we'll need it before merging. Please sign the CLA when you get a chance, then post a comment here saying !signed-cla

@telegraf-tiger telegraf-tiger bot added the feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin label Apr 4, 2023
@shantanoo-desai
Copy link
Contributor Author

Tests

One of the major concern with introducing tests for List and Get as well as ResolverFunc is the fact that Docker defaults to injecting secrets under /run directory. Assuming the tests can be written similar to jose plugin, creating temporary directories and files within them will fail because the Get method relies on the hard-coded path to /run/secrets. Another caveat is /run directory required privilege escalation which may not be desirable for CI tests.

I would like some guidance on how to proceed with testing this plugin which is inherently meant to be run in a docker container. Is there some provision to achieve the testing for /run directory?

cc @srebhan , @Hipska

@shantanoo-desai
Copy link
Contributor Author

!signed-cla

@Hipska
Copy link
Contributor

Hipska commented Apr 5, 2023

Hi, there is the testutil.Container, not sure if it can be used for this purpose as usually that's for running other apps.

@shantanoo-desai
Copy link
Contributor Author

I think test-containers won't work directly here because I realize now that secrets injection from Docker is actually via docker compose so I might have to perform a test with a docker-compose.yml file.

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this is still marked as a draft, this PR looks quite solid. I added some comments and would love to see a basic test with a dummy directory to get some more test coverage.

shantanoo-desai and others added 4 commits April 10, 2023 11:55
- add `path` variable to the plugin to cover better test coverage
  This `path` variable mentioned in the `sample.conf` comes with
  a note for the current docker compose where the value is default
  to `/run/secrets`
- refactor `docker.go` to address review points and improve the
  error messages
- add `docker_test.go` to conduct Tests for `List`, `Get`, `Resolver`
  and `Set`. These tests rely heavily on the Jose Plugin since the
  core functionality is similar since the introduction of `path`
  variable in the configuration

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
@shantanoo-desai shantanoo-desai marked this pull request as ready for review April 10, 2023 12:06
- set the default path to `/run/secrets` if no other path is explicitly
  mentioned.
- Improve the error handling for files / directory by return explicity
 what is the reason as opposed to generic error statements
- update test coverage by removing the path error checks, test for
  a non-existent path and check for substring in non-existent resolution

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @shantanoo-desai for the awesome plugin. A few comments from my side...

- add `docker` in the main README.md for secretstore plugins
- add `dynamic` configuration for dynamic secrets in `sample.conf`
- add additional example Compose file in README.md to provide a
  usage scenario with plugin
- add some additional links for Docker Secrets

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
-  add `dynamic` configuration for dynamic secrets
- provide checks for directory traversal errors
- adapt resolver to use dynamic configuration value instead of
  hard-coded boolean value

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
- add `testdata` directory that contains some dummy secret files
- better error handling using `Error.Contains` as opposed to simply
  `Error` wherever possible
- set `testdir` variable within Test cases with absolute path to
  `testdata` directory
- conduct separate `TestSetNotAvailable` case

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
@shantanoo-desai
Copy link
Contributor Author

Change Summary

  • Use testdata directory for testing
  • Refactor docker_test.go to adapt request changes (better error capturing)
  • Add more information in README.md
  • add dynamic option in sample.conf and adapt the resolver to pick this value as opposed to hard-coded boolean
  • add a Error check for permissions for d.Path with os.IsPermission(err) in addition to os.IsNotExist(err) in initialization of plugin

@shantanoo-desai
Copy link
Contributor Author

shantanoo-desai commented Apr 18, 2023

Local Test

Perform tests for plugin with a local docker container using the following files:

Dockerfile

FROM ubuntu:latest

WORKDIR /app

COPY https://<CIRCLECI_URL>_deb /app/telegraf_amd64.deb
COPY entrypoint.sh /app/entrypoint.sh
RUN  chmod +x /app/entrypoint.sh

RUN dpkg -i /app/telegraf_amd64.deb

ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["telegraf"]

docker-compose.yml

services:
  telegraf:
    image: test-telegraf:latest
    container_name: telegraf-opcua-docker
    user: "1000"
    network_mode: host
    env_file:
      - .env
    volumes:
      - ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
    secrets:
      - opcua_password
secrets:
  opcua_password:
    environment: OPCUA_PASSWORD

telegraf.conf

[agent]
    interval = "20s"
    round_interval = true
    metric_batch_size = 1000
    metric_buffer_limit = 10000
    collection_jitter = "0s"
    flush_interval = "10s"
    flush_jitter = "0s"
    precision = ""
    debug = true
    quiet = false
    hostname = ""
    omit_hostname = true

[[secretstores.docker]]
  id = "dockersecret_test"

[[outputs.file]]
  data_format = "json"

[[inputs.opcua]]
  ## Metric name
  name = "secrettest"
  endpoint = "opc.tcp://192.168.4.201:4840"
  connect_timeout = "60s"


  request_timeout = "60s"

  security_policy = "None"
  security_mode = "None"
  username = "OpcUser"

  password = "@{dockersecret_test:opcua_password}"
  timestamp = "source"

  nodes = [ {name="test", namespace="2", identifier_type="s", identifier="IX_SSC_LightBarrierOutsource_I4"}  ]

  data_format = "json"

entrypoint.sh

#!/bin/bash
set -e

if [ "${1:0:1}" = '-' ]; then
    set -- telegraf "$@"
fi

if [ $EUID -ne 0 ]; then
    exec "$@"
else
    # Allow telegraf to send ICMP packets and bind to privliged ports
    setcap cap_net_raw,cap_net_bind_service+ep /usr/bin/telegraf || echo "Failed to set additional capabilities on /usr/bin/telegraf"

    exec setpriv --reuid telegraf --init-groups "$@"
fi

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
it is essential to let the container run with `user` parameter in the
compose file since `/run/` directory is accessible only when the user
within the container is `root`. By providing the `user` value which is
typically the user id (via `id -u`), telegraf is able to read the values

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
@Hipska Hipska added ready for final review This pull request has been reviewed and/or tested by multiple users and is ready for a final review. plugin/secretstores new plugin labels Apr 20, 2023
Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shantanoo-desai thanks for the update, we are almost there... Just have one comment regarding the error handling in Init.

- Catch all the errors in order to provide a plausible explanation as to
  why the plugin failed to access

Signed-off-by: Shantanoo 'Shan' Desai <shantanoo.desai@gmail.com>
@telegraf-tiger
Copy link
Contributor

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect. Thanks a lot @shantanoo-desai for the nice contribution!

@srebhan srebhan assigned powersj and unassigned srebhan Apr 25, 2023
Copy link
Contributor

@powersj powersj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for taking the time to both propose this and work through the process of creating a PR! This will go out in v1.27.0 in June.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin new plugin plugin/secretstores ready for final review This pull request has been reviewed and/or tested by multiple users and is ready for a final review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow Credentials to be read from files for Docker Secrets
4 participants