Vulnerabilities run via crontab job (#9938)

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [ ] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)
- [ ] Documented any permissions changes
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.
- [ ] Added/updated tests
- [ ] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [ ] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).

---------

Co-authored-by: Benjamin Edwards <edwards.benw@gmail.com>
This commit is contained in:
Zachary Winnerman 2023-02-22 12:35:40 -05:00 committed by GitHub
parent 2e870004e5
commit 99b9c24b0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 362 additions and 3 deletions

View file

@ -0,0 +1,344 @@
---
apiVersion: batch/v1
kind: CronJob
metadata:
labels:
app: fleet
chart: fleet
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: {{ .Values.fleetName }}
namespace: {{ .Release.Namespace }}
spec:
schedule: "{{ .Values.crons.vulnerabilities }}"
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
containers:
- name: {{ .Values.fleetName }}
imagePullPolicy: Always
command: [/usr/bin/fleet]
args: ["vuln_processing"]
image: {{ .Values.imageRepo }}:{{ .Values.imageTag }}
ports:
- name: {{ .Values.fleetName }}
containerPort: {{ .Values.fleet.listenPort }}
resources:
limits:
cpu: {{ .Values.resources.limits.cpu }}
memory: {{ .Values.resources.limits.memory }}
requests:
cpu: {{ .Values.resources.requests.cpu }}
memory: {{ .Values.resources.requests.memory }}
env:
## BEGIN FLEET SECTION
- name: FLEET_SERVER_SANDBOX_ENABLED
value: "1"
- name: FLEET_LICENSE_ENFORCE_HOST_LIMIT
value: "true"
- name: FLEET_VULNERABILITIES_DATABASES_PATH
value: /tmp/vuln
{{- if ne .Values.packaging.enrollSecret "" }}
- name: FLEET_PACKAGING_GLOBAL_ENROLL_SECRET
value: "{{ .Values.packaging.enrollSecret }}"
- name: FLEET_PACKAGING_S3_BUCKET
value: "{{ .Values.packaging.s3.bucket }}"
- name: FLEET_PACKAGING_S3_PREFIX
value: "{{ .Values.packaging.s3.prefix }}"
{{- end }}
- name: FLEET_SERVER_ADDRESS
value: "0.0.0.0:{{ .Values.fleet.listenPort }}"
- name: FLEET_AUTH_BCRYPT_COST
value: "{{ .Values.fleet.auth.bcryptCost }}"
- name: FLEET_AUTH_SALT_KEY_SIZE
value: "{{ .Values.fleet.auth.saltKeySize }}"
- name: FLEET_APP_TOKEN_KEY_SIZE
value: "{{ .Values.fleet.app.tokenKeySize }}"
- name: FLEET_APP_TOKEN_VALIDITY_PERIOD
value: "{{ .Values.fleet.app.inviteTokenValidityPeriod }}"
- name: FLEET_SESSION_KEY_SIZE
value: "{{ .Values.fleet.session.keySize }}"
- name: FLEET_SESSION_DURATION
value: "{{ .Values.fleet.session.duration }}"
- name: FLEET_LOGGING_DEBUG
value: "{{ .Values.fleet.logging.debug }}"
- name: FLEET_LOGGING_JSON
value: "{{ .Values.fleet.logging.json }}"
- name: FLEET_LOGGING_DISABLE_BANNER
value: "{{ .Values.fleet.logging.disableBanner }}"
- name: FLEET_SERVER_TLS
value: "{{ .Values.fleet.tls.enabled }}"
{{- if .Values.fleet.tls.enabled }}
- name: FLEET_SERVER_TLS_COMPATIBILITY
value: "{{ .Values.fleet.tls.compatibility }}"
- name: FLEET_SERVER_CERT
value: "/secrets/tls/{{ .Values.fleet.tls.certSecretKey }}"
- name: FLEET_SERVER_KEY
value: "/secrets/tls/{{ .Values.fleet.tls.keySecretKey }}"
{{- end }}
{{- if ne .Values.fleet.carving.s3.bucketName "" }}
- name: FLEET_S3_BUCKET
value: "{{ .Values.fleet.carving.s3.bucketName }}"
- name: FLEET_S3_PREFIX
value: "{{ .Values.fleet.carving.s3.prefix }}"
{{- if ne .Values.fleet.carving.s3.accessKeyID "" }}
- name: FLEET_S3_ACCESS_KEY_ID
value: "{{ .Values.fleet.carving.s3.accessKeyID }}"
- name: FLEET_S3_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: "{{ .Values.fleet.secretName }}"
key: "{{ .Values.fleet.carving.s3.secretKey }}"
{{ else }}
- name: FLEET_S3_STS_ASSUME_ROLE_ARN
value: "{{ .Values.fleet.carving.s3.stsAssumeRoleARN }}"
{{- end }}
{{- end }}
## END FLEET SECTION
## BEGIN MYSQL SECTION
- name: FLEET_MYSQL_ADDRESS
value: "{{ .Values.mysql.address }}"
- name: FLEET_MYSQL_DATABASE
value: "{{ .Values.mysql.database }}"
- name: FLEET_MYSQL_USERNAME
value: "{{ .Values.mysql.username }}"
- name: FLEET_MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.mysql.secretName }}
key: {{ .Values.mysql.passwordKey }}
- name: FLEET_MYSQL_MAX_OPEN_CONNS
value: "{{ .Values.mysql.maxOpenConns }}"
- name: FLEET_MYSQL_MAX_IDLE_CONNS
value: "{{ .Values.mysql.maxIdleConns }}"
- name: FLEET_MYSQL_CONN_MAX_LIFETIME
value: "{{ .Values.mysql.connMaxLifetime }}"
{{- if .Values.mysql.tls.enabled }}
- name: FLEET_MYSQL_TLS_CA
value: "/secrets/mysql/{{ .Values.mysql.tls.caCertKey }}"
- name: FLEET_MYSQL_TLS_CERT
value: "/secrets/mysql/{{ .Values.mysql.tls.certKey }}"
- name: FLEET_MYSQL_TLS_KEY
value: "/secrets/mysql/{{ .Values.mysql.tls.keyKey }}"
- name: FLEET_MYSQL_TLS_CONFIG
value: "{{ .Values.mysql.tls.config }}"
- name: FLEET_MYSQL_TLS_SERVER_NAME
value: "{{ .Values.mysql.tls.serverName }}"
{{- end }}
## END MYSQL SECTION
## BEGIN REDIS SECTION
- name: FLEET_REDIS_ADDRESS
value: "{{ .Values.redis.address }}"
- name: FLEET_REDIS_DATABASE
value: "{{ .Values.redis.database }}"
{{- if .Values.redis.usePassword }}
- name: FLEET_REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: "{{ .Values.redis.secretName }}"
key: "{{ .Values.redis.passwordKey }}"
{{- end }}
## END REDIS SECTION
## BEGIN OSQUERY SECTION
- name: FLEET_OSQUERY_NODE_KEY_SIZE
value: "{{ .Values.osquery.nodeKeySize }}"
- name: FLEET_OSQUERY_LABEL_UPDATE_INTERVAL
value: "{{ .Values.osquery.labelUpdateInterval }}"
- name: FLEET_OSQUERY_DETAIL_UPDATE_INTERVAL
value: "{{ .Values.osquery.detailUpdateInterval }}"
- name: FLEET_OSQUERY_STATUS_LOG_PLUGIN
value: "{{ .Values.osquery.logging.statusPlugin }}"
- name: FLEET_OSQUERY_RESULT_LOG_PLUGIN
value: "{{ .Values.osquery.logging.resultPlugin }}"
{{- if eq .Values.osquery.logging.statusPlugin "filesystem" }}
- name: FLEET_FILESYSTEM_STATUS_LOG_FILE
value: "/logs/{{ .Values.osquery.logging.filesystem.statusLogFile }}"
{{- end }}
{{- if eq .Values.osquery.logging.resultPlugin "filesystem" }}
- name: FLEET_FILESYSTEM_RESULT_LOG_FILE
value: "/logs/{{ .Values.osquery.logging.filesystem.resultLogFile }}"
{{- end }}
{{- if or (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
- name: FLEET_FILESYSTEM_ENABLE_LOG_ROTATION
value: "{{ .Values.osquery.logging.filesystem.enableRotation }}"
- name: FLEET_FILESYSTEM_ENABLE_LOG_COMPRESSION
value: "{{ .Values.osquery.logging.filesystem.enableCompression }}"
{{- end }}
{{- if or (eq .Values.osquery.logging.statusPlugin "firehose") (eq .Values.osquery.logging.resultPlugin "firehose") }}
- name: FLEET_FIREHOSE_REGION
value: "{{ .Values.osquery.logging.firehose.region }}"
{{- if eq .Values.osquery.logging.statusPlugin "firehose" }}
- name: FLEET_FIREHOSE_STATUS_STREAM
value: "{{ .Values.osquery.logging.firehose.statusStream }}"
{{- end }}
{{- if eq .Values.osquery.logging.resultPlugin "firehose" }}
- name: FLEET_FIREHOSE_RESULT_STREAM
value: "{{ .Values.osquery.logging.firehose.resultStream }}"
{{- end }}
{{- if ne .Values.osquery.logging.firehose.accessKeyID "" }}
- name: FLEET_FIREHOSE_ACCESS_KEY_ID
value: "{{ .Values.osquery.logging.firehose.accessKeyID }}"
- name: FLEET_FIREHOSE_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: "{{ .Values.osquery.secretName }}"
key: "{{ .Values.osquery.logging.firehose.secretKey }}"
{{ else }}
- name: FLEET_FIREHOSE_STS_ASSUME_ROLE_ARN
value: "{{ .Values.osquery.logging.firehose.stsAssumeRoleARN }}"
{{- end }}
{{- end }}
{{- if or (eq .Values.osquery.logging.statusPlugin "kinesis") (eq .Values.osquery.logging.resultPlugin "kinesis") }}
- name: FLEET_KINESIS_REGION
value: "{{ .Values.osquery.logging.kinesis.region }}"
{{- if eq .Values.osquery.logging.statusPlugin "kinesis" }}
- name: FLEET_KINESIS_STATUS_STREAM
value: "{{ .Values.osquery.logging.kinesis.statusStream }}"
{{- end }}
{{- if eq .Values.osquery.logging.resultPlugin "kinesis" }}
- name: FLEET_KINESIS_RESULT_STREAM
value: "{{ .Values.osquery.logging.kinesis.resultStream }}"
{{- end }}
{{- if ne .Values.osquery.logging.kinesis.accessKeyID "" }}
- name: FLEET_KINESIS_ACCESS_KEY_ID
value: "{{ .Values.osquery.logging.kinesis.accessKeyID }}"
- name: FLEET_KINESIS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: "{{ .Values.osquery.secretName }}"
key: "{{ .Values.osquery.logging.kinesis.secretKey }}"
{{ else }}
- name: FLEET_KINESIS_STS_ASSUME_ROLE_ARN
value: "{{ .Values.osquery.logging.kinesis.stsAssumeRoleARN }}"
{{- end }}
{{- end }}
{{- if or (eq .Values.osquery.logging.statusPlugin "lambda") (eq .Values.osquery.logging.resultPlugin "lambda") }}
- name: FLEET_LAMBDA_REGION
value: "{{ .Values.osquery.logging.lambda.region }}"
{{- if eq .Values.osquery.logging.statusPlugin "lambda" }}
- name: FLEET_LAMBDA_STATUS_FUNCTION
value: "{{ .Values.osquery.logging.lambda.statusFunction }}"
{{- end }}
{{- if eq .Values.osquery.logging.resultPlugin "lambda" }}
- name: FLEET_LAMBDA_RESULT_FUNCTION
value: "{{ .Values.osquery.logging.lambda.resultFunction }}"
{{- end }}
{{- if ne .Values.osquery.logging.lambda.accessKeyID "" }}
- name: FLEET_LAMBDA_ACCESS_KEY_ID
value: "{{ .Values.osquery.logging.lambda.accessKeyID }}"
- name: FLEET_LAMBDA_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: "{{ .Values.osquery.secretName }}"
key: "{{ .Values.osquery.logging.lambda.secretKey }}"
{{ else }}
- name: FLEET_LAMBDA_STS_ASSUME_ROLE_ARN
value: "{{ .Values.osquery.logging.lambda.stsAssumeRoleARN }}"
{{- end }}
{{- end }}
{{- if or (eq .Values.osquery.logging.statusPlugin "pubsub") (eq .Values.osquery.logging.resultPlugin "pubsub") }}
- name: FLEET_PUBSUB_PROJECT
value: "{{ .Values.osquery.logging.pubsub.project }}"
{{- end }}
{{- if eq .Values.osquery.logging.statusPlugin "pubsub" }}
- name: FLEET_PUBSUB_STATUS_TOPIC
value: "{{ .Values.osquery.logging.pubsub.statusTopic }}"
{{- end }}
{{- if eq .Values.osquery.logging.resultPlugin "pubsub" }}
- name: FLEET_PUBSUB_RESULT_TOPIC
value: "{{ .Values.osquery.logging.pubsub.resultTopic }}"
{{- end }}
## END OSQUERY SECTION
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
privileged: false
readOnlyRootFilesystem: true
runAsGroup: 3333
runAsUser: 3333
runAsNonRoot: true
livenessProbe:
httpGet:
path: /healthz
port: {{ .Values.fleet.listenPort }}
timeoutSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: {{ .Values.fleet.listenPort }}
timeoutSeconds: 10
{{- if or (.Values.fleet.tls.enabled) (.Values.mysql.tls.enabled) (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
volumeMounts:
{{- if .Values.fleet.tls.enabled }}
- name: {{ .Values.fleetName }}-tls
readOnly: true
mountPath: /secrets/tls
{{- end }}
{{- if .Values.mysql.tls.enabled }}
- name: mysql-tls
readOnly: true
mountPath: /secrets/mysql
{{- end }}
{{- if or (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
- name: osquery-logs
mountPath: /logs
{{- end }}
- name: tmp
mountPath: /tmp
{{- end }}
{{- if .Values.gke.cloudSQL.enableProxy }}
- name: cloudsql-proxy
image: "gcr.io/cloudsql-docker/gce-proxy:{{ .Values.gke.cloudSQL.imageTag }}"
command:
- "/cloud_sql_proxy"
- "-verbose={{ .Values.gke.cloudSQL.verbose}}"
- "-instances={{ .Values.gke.cloudSQL.instanceName }}=tcp:3306"
resources:
limits:
cpu: 0.5 # 500Mhz
memory: 150Mi
requests:
cpu: 0.1 # 100Mhz
memory: 50Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
privileged: false
readOnlyRootFilesystem: true
runAsGroup: 3333
runAsUser: 3333
runAsNonRoot: true
{{- end }}
hostPID: false
hostNetwork: false
hostIPC: false
serviceAccountName: {{ .Values.fleetName }}
{{- if or (.Values.fleet.tls.enabled) (.Values.mysql.tls.enabled) (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
volumes:
{{- if .Values.fleet.tls.enabled }}
- name: {{ .Values.fleetName }}-tls
secret:
secretName: "{{ .Values.fleet.secretName }}"
{{- end }}
{{- if .Values.mysql.tls.enabled }}
- name: mysql-tls
secret:
secretName: "{{ .Values.mysql.secretName }}"
{{- end }}
{{- if or (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
- name: osquery-logs
emptyDir:
sizeLimit: "{{ .Values.osquery.logging.filesystem.volumeSize }}"
{{- end }}
- name: tmp
emptyDir:
{{- end }}

View file

@ -50,10 +50,12 @@ spec:
memory: {{ .Values.resources.requests.memory }}
env:
## BEGIN FLEET SECTION
- name: FLEET_VULNERABILITIES_EXTERNAL_SCHEDULED
value: "true"
- name: FLEET_SESSION_DURATION
value: "1y"
- name: FLEET_SERVER_SANDBOX_ENABLED
value: "1"
- name: FLEET_VULNERABILITIES_PERIODICITY
value: "15m"
- name: FLEET_LICENSE_ENFORCE_HOST_LIMIT
value: "true"
- name: FLEET_VULNERABILITIES_DATABASES_PATH

View file

@ -187,3 +187,6 @@ gke:
useManagedCertificate: false
# Workload Identity allows the K8s service account to assume the IAM permissions of a GCP service account
workloadIdentityEmail: ""
crons:
vulnerabilities: "0,15,30,45 * * * *"

View file

@ -81,6 +81,11 @@ resource "random_password" "db" {
length = 8
}
resource "random_integer" "cron_offset" {
min = 0
max = 14
}
resource "helm_release" "main" {
name = terraform.workspace
chart = "${path.module}/fleet"
@ -157,7 +162,7 @@ resource "helm_release" "main" {
set {
name = "imageTag"
value = "v4.27.1"
value = "v4.26.0-1"
}
set {
@ -184,6 +189,11 @@ resource "helm_release" "main" {
name = "serviceAccountAnnotations.eks\\.amazonaws\\.com/role-arn"
value = aws_iam_role.main.arn
}
set {
name = "crons.vulnerabilities"
value = "${random_integer.cron_offset.result}\\,${random_integer.cron_offset.result + 15}\\,${random_integer.cron_offset.result + 30}\\,${random_integer.cron_offset.result + 45} * * * *"
}
}
data "aws_iam_policy_document" "main" {