dropbox / dbxcli

A command line client for Dropbox built using the Go SDK
Other
1.05k stars 101 forks source link

Authentication inside a docker container #117

Open scotartt opened 5 years ago

scotartt commented 5 years ago

I want to use this tool to push a build artefact into my Dropbox, from a Gitlab CI/CD process which is running inside a disposable Docker container spawned (and then destroyed) by a GitLab CI/CD runner.

I would like it to be fully scriptable inside a Makefile or .gitlab-ci.yml and supplied the necessary credentials from a secrets store into its environment. Which is pretty normal ci/cd practice. I have 2FA on my regular dropbox login, so I need some other way to gain authentication without any manual intervention. In an AWS environment it would be the sort of thing we'd do with S3. The artefact is a PDF which is my PhD thesis, so I can't really use a nexus repo or similar.

I thought that I'd be able to extract an api secret encrypted inside my CI/CD pipeline and pushed into the container's environment, especially once I saw this commit - commit cf9b43e9e49b19df862f53423f0176a25a88bc61 which appears to have added variable:

personalAppKey      = getEnv("DROPBOX_PERSONAL_APP_KEY", personalAppKey)
personalAppSecret   = getEnv("DROPBOX_PERSONAL_APP_SECRET", personalAppSecret)

When I tried testing it inside a docker container on my local Mac, it seems that the authorisation I set up (when I first ran dbxcli account and it told me to get a key from https://www.dropbox.com/1/oauth2/authorize?client_id=07o23gulcj8qi69&response_type=code&state=state) doesn't appear to survive the container stop and restart. Attempting to re-apply the key I was given in the first attempt in a new instance results in:

Error: oauth2: cannot fetch token: 400 Bad Request
Response: {"error_description": "code has expired (within the last hour)", "error": "invalid_grant"}

How do I achieve this? Is it possible?

pascalandy commented 5 years ago

The README says to replace these values: Screen Shot 2019-07-19 at 6 56 23 PM

I agree with you, we need to pass these VAR at runtime to have a clean docker container as we DON'T want to insert API key in the docker image.

pascalandy commented 5 years ago

A hack we can do is to have an ENTRYPOINT to sed 'KEYS' from and ARG pushed at runtime.

pascalandy commented 5 years ago

I guess I'll stick with https://rclone.org/dropbox/.

pascalandy commented 5 years ago

Here is how my Dockerfile would look like:

ARG app_version="3.0.0-r1"
ARG GOLANG_VERSION="1.12"
ARG ALPINE_VERSION="3.9"
ARG CREATED_DATE="not-set"
ARG SOURCE_COMMIT="not-set"

# LAYER build — — — — — — — — — — — — — — — — — — — — — — — — — — —
# using debian as we can't install gox on alpine
FROM golang:${GOLANG_VERSION} AS build

ARG app_version
ARG BUILD_DATE
ARG VCS_REF

RUN apt-get update && apt-get install -qqy \
      git gox ca-certificates upx

WORKDIR $HOME/go
RUN go get github.com/dropbox/dbxcli
WORKDIR /go/src/github.com/dropbox/dbxcli

#Now we need to pause for a second to get development keys.
#Head to https://www.dropbox.com/developers/apps (sign in if necessary) and choose "Create app". Use the Dropbox API and give it Full Dropbox access. Name and create the app.
#You'll be presented with a dashboard with an "App key" and an "App secret".
#Replace the value for personalAppKey in root.go with the key from the webpage.
#Replace the value for personalAppSecret with the secret from the webpage.

RUN go build

# compress (reduce size 13.0M to 5.7MO about 46%)
RUN upx dbxcli && upx -t dbxcli

# confirm the app is running normally
RUN dbxcli --help

# LAYER final — — — — — — — — — — — — — — — — — — — — — — — — — — —
FROM alpine:${ALPINE_VERSION} AS final

ARG app_version
ARG BUILD_DATE
ARG VCS_REF
ARG CREATED_DATE
ARG SOURCE_COMMIT
ARG ALPINE_VERSION
ARG GOLANG_VERSION

ENV CREATED_DATE=${CREATED_DATE}
ENV SOURCE_COMMIT=${SOURCE_COMMIT}
ENV ALPINE_VERSION=${ALPINE_VERSION}
ENV GOLANG_VERSION={GOLANG_VERSION}

RUN set -eux && \
    apk --update --no-cache add \
      tzdata && \
      cp /usr/share/zoneinfo/America/New_York /etc/localtime      && \
      echo "America/New_York" > /etc/timezone                     && \
      apk del tzdata                                              && \
    rm -rf /var/cache/apk/* /tmp/*                                ;

# best practice from https://github.com/opencontainers/image-spec/blob/master/annotations.md
LABEL org.opencontainers.image.authors="Pascal Andy https://firepress.org/en/contact/"  \
      org.opencontainers.image.vendors="https://firepress.org/"                         \
      org.opencontainers.image.created="${CREATED_DATE}"                                \
      org.opencontainers.image.revision="${SOURCE_COMMIT}"                              \
      org.opencontainers.image.title="dpxcli ${app_version}"                           \
      org.opencontainers.image.description="Docker image for dpxcli"                    \
      org.opencontainers.image.url="https://hub.docker.com/r"                           \
      org.opencontainers.image.source="not shared at the moment"                        \
      org.opencontainers.image.licenses="LICENSE.md"                                    \
      org.firepress.image.alpineversion="${ALPINE_VERSION}"                             \
      org.firepress.image.goversion="${GOLANG_VERSION}"                                 \
      org.firepress.image.schemaversion="1.0"

# copy caddy binary and ca certs
COPY --from=build /go/src/github.com/dropbox/dbxcli/ /bin/dbxcli/

VOLUME ["/bin"]
WORKDIR /srv

ENTRYPOINT [ sed script to replace keys in file root.go ]
CMD [ "/dbxcli", "--help" ]

I won't continue building this. But it would be easy to do it. In the ENTRYPOINT, create a bash script that will replace the keys passed as an ENV on runtime. The final image could run from scratch (I just like to have alpine as many containers are already using it.)

Cheers!

sabjorn commented 4 years ago

@pascalandy

A hack we can do is to have an ENTRYPOINT to sed 'KEYS' from and ARG pushed at runtime.

I agree, it can be really nice for an application to handle this stuff by itself automatically (like NGINX). However, what you've mentioned isn't really a hack. ENTRYPOINTs are really there to do any work necessary to setup your container before running the CMD.

sed works great for this but there's also envsubst.