setup ftp .ssh directory with public/private key info with docker - java

I have an helm-chart that references sftp key string:
apiVersion: v1
kind: Pod
metadata:
name: envar-demo
labels:
purpose: demonstrate-envars
spec:
containers:
- name: envar-demo-container
image: gcr.io/google-samples/node-hello:1.0
env:
- name: PUBLIC_KEY
value: secretFromVault
- name: PRIVATE_KEY
value: secretFromVault
I have a DockerFile that sets up my user and creates an .ssh directory
RUN adduser -D -s /bin/bash -h /test_user test_user &&\
mkdir /test_user/.ssh/ &&\
chmod 700 /test_usr/.ssh/ &&
In this directory, I want to create the id_rsa file and input the private key string and create a knownhost file and input the reference of the public key so I can establishing remote connection target server?
How can I do this using dockerfile? Or is there a better way to do this? My sftp client code references these two files.

Instead of making your secrets as environment variable, you need to mount them as a file.
apiVersion: v1
kind: Pod
metadata:
name: envar-demo
labels:
purpose: demonstrate-envars
spec:
containers:
- name: envar-demo-container
image: gcr.io/google-samples/node-hello:1.0
volumeMounts:
- name: keys
mountPath: /home/test_user/.ssh
subPath: id_rsa.pub
- name: keys
mountPath: /home/test_user/.ssh
subPath: id_rsa
volumes:
- name: keys
secret:
secretName: secretFromVault
defaultMode: 384
You will need to update the secret name from PUBLIC_KEY and PRIVATE_KEY to id_rsa.pub and id_rsa in this case.

You could add VOLUME /test_usr/.ssh to your Dockerfile and then mount a local directory to that volume. In the local directory you can generate the keys with ssh-keygen and the knownhosts if needed.

Related

How to read kubernetes secrets values from volume mount in spring boot

My code is below
apiVersion: v1
kind: Secret
metadata:
name: test-secret
namespace: default
type: Opaque
data:
secret.db_user: |
dGVzdA==
secret.db_password: |
dGVzdA==
And then i mount this as volume mount in the deployment section, Now i want to read this secret and map to spring.datasource.username and spring.datasource.passowrd without env configuration in the deployment section. Read should be from java code. How can i do that.
You can either mount the secrets as environment variables OR as files into a pod. The best remains to mount them as environment variables for me (https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables) but all cases are differents.
You can use "subPath" to mount the secret key to a specific subdirectory without overwriting its whole content (that means only mount the file in the existing directory among with others existing files for example).
volumeMounts:
- mountPath: "/var/my-app/db_creds"
subPath: db_creds
name: db-creds
readOnly: true
volumes:
- name: db-creds
secret:
secretName: test-secret
(or you can mount both username and password into two separate files)
If you want to read a file with spring (here with spring environment varialbes but you can do the same in your app.properties, you get the point), here is an example with my truststore that is a file (the ${SSL_TRUSTSTORE} environment variable contains the path to the truststore:
SPRING_KAFKA_SSL_TRUSTSTORE_LOCATION: "file://${SSL_TRUSTSTORE}"

Not able to access placeholder, which is added as secret and the secret is mounted as volume rather than environment variable

My password placeholder in Application.yaml in spring boot project:
password: {DB_PASSWORD}
My secret file:
apiVersion: v1
data:
DB_PASSWORD: QXBwX3NhXzA1X2pzZHVlbmRfMzIx
kind: Secret
type: Opaque
metadata:
name: test-secret
My Deployment config file part:
spec:
containers:
- envFrom:
- configMapRef:
name: gb-svc-rpt-dtld-cc
image: >-
artifactory.global.standardchartered.com/colt/gb-svc-reports-dataloader-cc/gb-svc-reports-dataloader-cc-develop#sha256:c8b7e210c18556155d8314eb41965fac57c1c9560078e3f14bf7407dbde564fb
imagePullPolicy: Always
name: gb-svc-rpt-dtld-cc
ports:
- containerPort: 8819
protocol: TCP
volumeMounts:
- mountPath: /etc/secret
name: secret-test
volumes:
- name: secret-test
secret:
defaultMode: 420
secretName: test-secret
I'm able to see the secrets added in /etc/secret path also. But it is not getting referred in placeholders and getting error while server startup.
Could not resolve placeholder 'DB_PASSWORD' in value "${DB_PASSWORD}"
Note: Same code works if i add the secret as environment variable in deployment config
As I understand from your question you are trying to mount secret to a pod as an environment variable. In kubernetes secrets are able to mount as a volume (which you did in the attached code) and as env variable (as you like to do)
For that you should use:
spec:
containers:
- env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: DB_PASSWORD
name: test-secret
image: "fedora:29"
name: my_app

Reading Kube Secrets from Java Program

I'm working on a library to read secrets from a given directory that I've got easily up and running with Docker Swarm by using the /run/secrets directory as the defined place to read secrets from. I'd like to do the same for a Kubernetes deployment but looking online I see many guides that advise using various Kubernetes APIs and libraries. Is it possible to simply read from disk as it is with Docker Swarm? If so, what is the directory that these are stored in?
Please read the documentation
I see 2 practical ways to access the k8s secrets:
Mount the secret as a file
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
Expose the secret as an environmental variable
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password

Dockerized Spring Boot app not using mounted Kubernetes ConfigMap (application.properties)

I have a problem where in my dockerized Spring Boot application is not using the application.properties I stored in a configMap.
However, I can see and confirm that my configMap has been mounted properly in the right directory of my Spring Boot app when I enter the pod's shell.
Note that I have an application.properties by default wherein Kubernetes mounts / overwrites it later on.
It seems that the Spring Boot uses the first application.properties and when k8s overwrites it, apparently, it doesn't use it.
It seems that, apparently, what happens is:
run the .jar file inside the Dockerized Spring Boot app
use the first/default application.properties file on runtime
Kubernetes proceeds to mount the configMap
mount / overwrite success, but how will Spring Boot use this one since it's already running?
Here is the Dockerfile of my Spring Boot / Docker image for reference:
FROM maven:3.5.4-jdk-8-alpine
# Copy whole source code to the docker image
# Note of .dockerignore, this ensures that folders such as `target` is not copied
WORKDIR /usr/src/myproject
COPY . /usr/src/myproject/
RUN mvn clean package -DskipTests
WORKDIR /usr/src/my-project-app
RUN cp /usr/src/myproject/target/*.jar ./my-project-app.jar
EXPOSE 8080
CMD ["java", "-jar", "my-project-app.jar"]
Here's my Kubernetes deployment .yaml file for reference:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-project-api
namespace: my-cluster
labels:
app: my-project-api
spec:
replicas: 1
selector:
matchLabels:
app: my-project-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: my-project-api
spec:
containers:
- name: my-project-api
image: "my-project:latest"
imagePullPolicy: Always
env:
.
.
.
volumeMounts:
- name: my-project-config
mountPath: /usr/src/my-project/my-project-service/src/main/resources/config/application.properties
ports:
- containerPort: 8080
name: my-project-api
protocol: TCP
volumes:
# Name of the volume
- name: my-project-config
# Get a ConfigMap with this name and attach to this volume
configMap:
name: my-project-config
And my configMap for reference:
kind: ConfigMap
apiVersion: v1
data:
application.properties: |-
# This comment means that this is coming from k8s ConfigMap. Nice!
server.port=8999
.
.
.
.
metadata:
name: my-project-config
namespace: my-cluster
Any help is greatly appreciated... Thank you so much.. :)
The thing is that /src/main/resources/application.properties that your application uses is the one that is inside the jar file by default. If you open your jar, you should see it there.
That being said, your expectations to mount a /src/main/resources directory where your jar is are not going to be fulfilled, unfortunately.
These are the docs you should be looking at.
I won't go into much detail as it's explained pretty good in the docs but I will say that you are better off explicitly declaring your config location so that new people on the project know from where the config is coming from right off the bat.
You can do something like this:
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-project-api
labels:
app: my-project-api
spec:
selector:
matchLabels:
app: my-project-api
template:
metadata:
labels:
app: my-project-api
spec:
containers:
- name: my-project-api
image: "my-project:latest"
imagePullPolicy: Always
env:
- name: JAVA_OPTS
value: "-Dspring.config.location=/opt/config"
.
.
.
volumeMounts:
- name: my-project-config
mountPath: /opt/config
ports:
- containerPort: 8080
volumes:
- name: my-project-config
configMap:
name: my-project-config
Hope that helps,
Cheers!
I did slightly differently. I made sure I have mounted application.properties at config/. i.e; below is my example mounted application.properties (below commands show the values in pod - i.e; after kubectl exec -it into the pod)
/ # pwd
/
/ # cat config/application.properties
logback.access.enabled=false
management.endpoints.web.exposure.include=health, loggers, beans, configprops, env
Basically, the trick is based on the link in the above answer. Below is an excerpt from the link in which it does say application.properties will be picked from config/. So, I made sure my environment (dev, test, prod) specific config map was mounted at config/. Do note there is precedence for the below list (per the link: locations higher in the list override lower items)
A /config subdir of the current directory.
The current directory
A classpath /config package
The classpath root
Below is the config map definition (just pasted data section)
data:
application.properties: |+
logback.access.enabled={{.Values.logacbkAccessEnabled}}
management.endpoints.web.exposure.include=health, loggers, beans, configprops, env
And you can also see from actuator/env endpoint SpringBootApp did pick those values.
{
"name": "Config resource 'file [config/application.properties]' via location 'optional:file:./config/'",
"properties": {
"logback.access.enabled": {
"value": "false",
"origin": "URL [file:config/application.properties] - 1:24"
},
"management.endpoints.web.exposure.include": {
"value": "health, loggers, beans, configprops, env",
"origin": "URL [file:config/application.properties] - 2:43"
}
}
},

Programmatically get the name of the pod that a container belongs to in Kubernetes?

Is there a way to programmatically get the name of the pod that a container belongs to in Kubernetes? If so how? I'm using fabric8's java client but curl or something similar will be fine as well.
Note that I don't want to find the pod using a specific label since then (I assume) I may not always find the right pod if it's scaled with a replication controller.
You can tell Kubernetes to put the pod name in an environment variable of your choice using the downward API.
For example:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
restartPolicy: Never
The pod name is written to /etc/hostname so it's possible to read it from there. In Java (which I'm using) you can also get the hostname (and thus the name of the pod) by calling System.getenv("HOSTNAME").

Categories