从 SCDF 执行任务时,数据库凭证作为部分作业参数公开

Posted

技术标签:

【中文标题】从 SCDF 执行任务时,数据库凭证作为部分作业参数公开【英文标题】:DB Credentials Exposed as part job parameters when executing a task from SCDF 【发布时间】:2020-10-05 17:29:54 【问题描述】:

我有自定义构建的 SCDF,它在 Openshift 中构建为 docker 映像,并在 server-deployment.yaml 中称为 docker 映像。我使用 Oracle db 来存储任务元数据,并且是这里的外部源。我在 configmap 中传递了所有 db 属性。 DB 密码经过 base64 编码并作为机密添加到配置映射中。 SCDF 正在使用这些 db 详细信息来存储任务元数据。

这些作业参数由 SCDF 传递给正在执行的作业。但是这些作业参数又是数据源属性,包括 configmap 中存在的 db 密码,正在作为作业参数和 batch_job_execution_params 表打印在日志中。

我认为在 configmap 中使用密码作为密码应该可以解决这个问题。但事实并非如此。下面是正在打印的作业参数的日志和表sn-p。

我想知道如何避免将这些 db 属性作为作业参数传递给正在执行的作业,以防止暴露凭据?

12-06-2020 18:12:38.540 [main] INFO org.springframework.batch.core.launch.support.SimpleJobLauncher.run - Job: 
[FlowJob: [name=Job]] launched with the following parameters: [
-spring.cloud.task.executionid=8010, 
-spring.cloud.data.flow.platformname=default, 
-spring.datasource.username=ACTUAL_USERNAME, 
-spring.cloud.task.name=Alljobs, 
Job.ID=1591985558466, 
-spring.datasource.password=ACTUAL_PASSWORD, 
-spring.datasource.driverClassName=oracle.jdbc.OracleDriver, 
-spring.datasource.url=DATASOURCE_URL, 
-spring.batch.job.names=Job_1]

为作业执行创建的 Pod - openshift 屏幕截图

数据库表

Custom SCDF Dockerfile.yaml
===========================
FROM maven:3.5.2-jdk-8-alpine AS MAVEN_BUILD

COPY pom.xml /build/
COPY src /build/src/

WORKDIR /build/
RUN mvn package

FROM openjdk:8-jre-alpine

WORKDIR /app
COPY --from=MAVEN_BUILD /build/target/BatchAdmin-0.0.1-SNAPSHOT.jar /app/

ENTRYPOINT ["java", "-jar", "BatchAdmin-0.0.1-SNAPSHOT.jar"]

Deployment.yaml
===============
apiVersion: apps/v1
kind: Deployment
metadata:
  name: scdf-server
  labels:
    app: scdf-server
spec:
  selector:
    matchLabels:
      app: scdf-server
  replicas: 1
  template:
    metadata:
      labels:
        app: scdf-server
    spec:
      containers:
      - name: scdf-server
        image: docker-registry.default.svc:5000/batchadmin/scdf-server #DockerImage
        imagePullPolicy: Always
        volumeMounts:
          - name: config
            mountPath: /config
            readOnly: true
        ports:
        - containerPort: 80
        livenessProbe:
          httpGet:
            path: /management/health
            port: 80
          initialDelaySeconds: 45
        readinessProbe:
          httpGet:
            path: /management/info
            port: 80
          initialDelaySeconds: 45
        resources:
          limits:
            cpu: 1.0
            memory: 2048Mi
          requests:
            cpu: 0.5
            memory: 1024Mi
        env:
        - name: KUBERNETES_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: "metadata.namespace"
        - name: SERVER_PORT
          value: '80'
        - name: SPRING_CLOUD_CONFIG_ENABLED
          value: 'false'
        - name: SPRING_CLOUD_DATAFLOW_FEATURES_ANALYTICS_ENABLED
          value: 'true'
        - name: SPRING_CLOUD_DATAFLOW_FEATURES_SCHEDULES_ENABLED
          value: 'true'
        - name: SPRING_CLOUD_DATAFLOW_TASK_COMPOSED_TASK_RUNNER_URI
          value: 'docker://springcloud/spring-cloud-dataflow-composed-task-runner:2.6.0.BUILD-SNAPSHOT'
        - name: SPRING_CLOUD_KUBERNETES_CONFIG_ENABLE_API
          value: 'true'
        - name: SPRING_CLOUD_KUBERNETES_SECRETS_ENABLE_API
          value: 'true'
        - name: SPRING_CLOUD_KUBERNETES_SECRETS_PATHS
          value: /etc/secrets
        - name: SPRING_CLOUD_DATAFLOW_FEATURES_TASKS_ENABLED
          value: 'true'
        - name: SPRING_CLOUD_KUBERNETES_CONFIG_NAME
          value: scdf-server
        - name: SPRING_CLOUD_DATAFLOW_SERVER_URI
          value: 'http://$SCDF_SERVER_SERVICE_HOST:$SCDF_SERVER_SERVICE_PORT'
          # Add Maven repo for metadata artifact resolution for all stream apps
        - name: SPRING_APPLICATION_JSON
          value: " \"maven\":  \"local-repository\": null, \"remote-repositories\":  \"repo1\":  \"url\": \"https://repo.spring.io/libs-snapshot\"   "
      serviceAccountName: scdf-sa
      volumes:
        - name: config
          configMap:
            name: scdf-server
            items:
            - key: application.yaml
              path: application.yaml


#- name: SPRING_CLOUD_DATAFLOW_FEATURES_TASKS_ENABLED
#value : 'true'

server-config.yaml
==================
apiVersion: v1
kind: ConfigMap
metadata:
  name: scdf-server
  labels:
    app: scdf-server
data:
  application.yaml: |-
    spring:
      cloud:
        dataflow:
          task:
            platform:
              kubernetes:
                accounts:
                  default:
                    limits:
                        memory: 1024Mi
                        cpu: 2
                entry-point-style: exec
                image-pull-policy: always
      datasource:
        url: jdbc:oracle:thin:@db_url
        username: BATCH_APP
        password: $oracle-root-password
        driver-class-name: oracle.jdbc.OracleDriver
        testOnBorrow: true
        validationQuery: "SELECT 1"
      flyway:
        enabled: false
      jpa:
        hibernate:
          use-new-id-generator-mappings: true

oracle-secrets.yaml
===================
apiVersion: v1
kind: Secret
metadata:
  name: oracle
  labels:
    app: oracle
data:
  oracle-root-password: a2xldT3ederhgyzFCajE4YQ==

任何帮助将不胜感激。谢谢。

【问题讨论】:

我不确定我是否理解您的问题。你能澄清一下你的问题是什么吗? 用更多信息更新了问题。基本上,当作业通过 SCDF 在 kubernetes 平台上执行时,SCDF 传递的作业参数包含 db 凭据。如何避免? 这里正在跟踪:github.com/spring-cloud/spring-cloud-dataflow/issues/3985 【参考方案1】:

这不是一个完美的例子——但是你可以通过使用 logback 的特性来屏蔽日志中的密码(Spring Boot 使用的默认日志库)

将下面的配置放入你的logback,它将用****替换密码

<springProfile name="local">
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                %ddd-MM-yyyy HH:mm:ss.SSS [%thread] %-5level %logger36.%M - %replace(%msg)'password=\S*', 'password=****'%n
            </pattern>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console"/>
    </root>
</springProfile>

对于登录数据库的密码,看来我们运气不好。我们能做的最好的事情是把它放在一个单独的模式中,并拥有访问这些 SCDF 表的特定权限。

【讨论】:

感谢 Hoang 的回答。值得庆幸的是,作为其发布的一部分,它自己的 scdf 已经解决了这个问题。我将在单独的答案中提供这些详细信息。 感谢@Rajesh2389 的更新:)。我的团队也有类似的问题,我们还不能升级 SCDF。我会暂时保留答案,以防有人遇到同样的问题。【参考方案2】:

在 SCDF V2.6.2 中,团队修复了这个问题。数据库凭据不再在日志、POD 描述页面或数据库中公开。默认情况下,凭据是可见的。因此,遇到此问题的任何人都必须将以下环境变量添加为部署配置的一部分并将值设置为 true。

SPRING_CLOUD_DATAFLOW_TASK_USE_KUBERNETES_SECRETS_FOR_DB_CREDENTIALS = true

【讨论】:

很高兴他们修好了。我的团队仍然坚持使用 SCDF 1.7.x...

以上是关于从 SCDF 执行任务时,数据库凭证作为部分作业参数公开的主要内容,如果未能解决你的问题,请参考以下文章

获取无法序列化SCDF中任务的访问异常

保持 SCDF 中的计划作业执行,直到上一个作业执行完成

backoffLimit/maxCrashLoopBackOffRestarts 的使用

为从 SCDF 启动的批处理作业创建的 PODS 的 ConfigMap

azkaban作业参数使用介绍

Spring Cloud DataFlow 组合任务未启动