mirror of
https://github.com/enix/x509-certificate-exporter.git
synced 2026-08-23 22:16:39 +00:00
refact(exporter): delete whole repo in preparation for v2
BREAKING CHANGE : The project is being rewritten in go
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
stages:
|
||||
- build
|
||||
- release
|
||||
- publish
|
||||
|
||||
variables:
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
|
||||
|
||||
build:
|
||||
stage: build
|
||||
image: docker:stable-dind
|
||||
script:
|
||||
- echo "Logging to GitLab Container Registry with CI credentials..."
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
||||
- docker build --tag $IMAGE_TAG .
|
||||
- docker push $IMAGE_TAG
|
||||
|
||||
semantic-release:
|
||||
stage: release
|
||||
image: enix/semantic-release:gitlab
|
||||
only:
|
||||
- master
|
||||
except:
|
||||
- tags
|
||||
script:
|
||||
- semantic-release --ci
|
||||
|
||||
publish-docker-hub:
|
||||
stage: publish
|
||||
only:
|
||||
refs:
|
||||
- /^v([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/
|
||||
image: docker:stable
|
||||
script:
|
||||
- echo "Logging to GitLab Container Registry with CI credentials..."
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
||||
- docker pull $IMAGE_TAG
|
||||
- docker tag $IMAGE_TAG $DOCKER_HUB_REPOSITORY/$CI_PROJECT_NAME:${CI_COMMIT_REF_NAME:1}
|
||||
- echo "Logging to Docker Hub Registry with Enix credentials..."
|
||||
- docker login -u "$DOCKER_HUB_USER" -p "$DOCKER_HUB_PASSWORD"
|
||||
- echo "Push release $CI_COMMIT_REF_NAME ..."
|
||||
- docker push $DOCKER_HUB_REPOSITORY/$CI_PROJECT_NAME:${CI_COMMIT_REF_NAME:1}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
["@semantic-release/gitlab", {
|
||||
"gitlabUrl": "https://gitlab.enix.io"
|
||||
}]
|
||||
]
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
FROM python:3.7
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY x509-exporter .
|
||||
|
||||
EXPOSE 9090
|
||||
|
||||
ENTRYPOINT [ "python", "./x509-exporter" ]
|
||||
CMD ["--port=9090"]
|
||||
@@ -1,20 +0,0 @@
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1USXlOakV6TWpjek5Gb1hEVEk0TVRJeU16RXpNamN6TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBUEtYCkZKM0pRUDFlS1UvazMvV2sweWFLSEQvT2Y1cVdrMlAzMVV1aW9tNko5UlM2TWxOeFdERkJlcnF6UWlzQ0g2aisKYStzM3hpM2dmUXVlVnF6VCtQelRpNWgzSStHcFRnajlmdTh6WXkxbURiK3RveXRqSHVzOUU2RVF4ZnF0SGRUeAoza2RESlplVWJCZUdNSXlSR3FMeXNPT1BWdXB3UWI3MDFlZ1FyWHdtbExvcjJmaUxQR0FieUdBQjByY0ViQ1pECmh2MzA1bTZTRXY3WU9KTjRvVkwxTGpZRk5FdlpCVXFJTFIvS25DeGNKc3BXa2pQSU9tQi9VWElMbExjaElEaGwKQ2FaZWlvZWI3WlByY2Jaem5qYkhPY2lZaUlTSTUwSis2MXl3eHoxZzBKUDJpZnRiZmMwTC9QWVQ2SDl4MS94cQo0K1c1QUpXVmVWeVFJZWhmcDZjQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMTDhCNWxqTkhycGo0a0kxL0ZBSmZqaDhBa3UKTzdpMkhLR2RHZ0ZybUdMeUdaRTNSRERDa3I2UFpRdlVYQkhmTzM2dDc3S21wYW1FOTUrYTJkOWt6Yld3TUl3NQpSMERlKy95eHJDa3BRcTVma2lJQW9VMEIra1lGdmdmb1llMm9RUjBVSXN1SWNJcVNvQmtnUjlGQXYzdDBHV25iClZZa1VKOTlxQm5HT09OU1RLc09Ib29RemkrVnNJN0M3S1BvZTMzNkJaVnlWTTRHS1dJSnlNSTdPKysvUnFVK2YKa0FxQnVzcHBuZGxXREZsalZwNk5ydkhiZjRaaWxDbEluUVN0NHg3N0h6V0FSamo3Y3ZNb01nSEpEVXZJQS9NRwpIZEFYYjJ2N3VpZjhLTzFKK0Zza0tQdmVDdWNCeDhIUDlGTlIxNnZSSDVkZFBPK0xEU0xCMVNZZ3UrYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
server: https://127.0.0.1:6443
|
||||
name: default-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: default-cluster
|
||||
namespace: default
|
||||
user: default-auth
|
||||
name: default-context
|
||||
current-context: default-context
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: default-auth
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1USXlOakV6TWpjek5Gb1hEVEk0TVRJeU16RXpNamN6TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBUEtYCkZKM0pRUDFlS1UvazMvV2sweWFLSEQvT2Y1cVdrMlAzMVV1aW9tNko5UlM2TWxOeFdERkJlcnF6UWlzQ0g2aisKYStzM3hpM2dmUXVlVnF6VCtQelRpNWgzSStHcFRnajlmdTh6WXkxbURiK3RveXRqSHVzOUU2RVF4ZnF0SGRUeAoza2RESlplVWJCZUdNSXlSR3FMeXNPT1BWdXB3UWI3MDFlZ1FyWHdtbExvcjJmaUxQR0FieUdBQjByY0ViQ1pECmh2MzA1bTZTRXY3WU9KTjRvVkwxTGpZRk5FdlpCVXFJTFIvS25DeGNKc3BXa2pQSU9tQi9VWElMbExjaElEaGwKQ2FaZWlvZWI3WlByY2Jaem5qYkhPY2lZaUlTSTUwSis2MXl3eHoxZzBKUDJpZnRiZmMwTC9QWVQ2SDl4MS94cQo0K1c1QUpXVmVWeVFJZWhmcDZjQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMTDhCNWxqTkhycGo0a0kxL0ZBSmZqaDhBa3UKTzdpMkhLR2RHZ0ZybUdMeUdaRTNSRERDa3I2UFpRdlVYQkhmTzM2dDc3S21wYW1FOTUrYTJkOWt6Yld3TUl3NQpSMERlKy95eHJDa3BRcTVma2lJQW9VMEIra1lGdmdmb1llMm9RUjBVSXN1SWNJcVNvQmtnUjlGQXYzdDBHV25iClZZa1VKOTlxQm5HT09OU1RLc09Ib29RemkrVnNJN0M3S1BvZTMzNkJaVnlWTTRHS1dJSnlNSTdPKysvUnFVK2YKa0FxQnVzcHBuZGxXREZsalZwNk5ydkhiZjRaaWxDbEluUVN0NHg3N0h6V0FSamo3Y3ZNb01nSEpEVXZJQS9NRwpIZEFYYjJ2N3VpZjhLTzFKK0Zza0tQdmVDdWNCeDhIUDlGTlIxNnZSSDVkZFBPK0xEU0xCMVNZZ3UrYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
client-key-data: bG9sCg==
|
||||
@@ -1,20 +0,0 @@
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1USXlOakV6TWpjek5Gb1hEVEk0TVRJeU16RXpNamN6TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBUEtYCkZKM0pRUDFlS1UvazMvV2sweWFLSEQvT2Y1cVdrMlAzMVV1aW9tNko5UlM2TWxOeFdERkJlcnF6UWlzQ0g2aisKYStzM3hpM2dmUXVlVnF6VCtQelRpNWgzSStHcFRnajlmdTh6WXkxbURiK3RveXRqSHVzOUU2RVF4ZnF0SGRUeAoza2RESlplVWJCZUdNSXlSR3FMeXNPT1BWdXB3UWI3MDFlZ1FyWHdtbExvcjJmaUxQR0FieUdBQjByY0ViQ1pECmh2MzA1bTZTRXY3WU9KTjRvVkwxTGpZRk5FdlpCVXFJTFIvS25DeGNKc3BXa2pQSU9tQi9VWElMbExjaElEaGwKQ2FaZWlvZWI3WlByY2Jaem5qYkhPY2lZaUlTSTUwSis2MXl3eHoxZzBKUDJpZnRiZmMwTC9QWVQ2SDl4MS94cQo0K1c1QUpXVmVWeVFJZWhmcDZjQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMTDhCNWxqTkhycGo0a0kxL0ZBSmZqaDhBa3UKTzdpMkhLR2RHZ0ZybUdMeUdaRTNSRERDa3I2UFpRdlVYQkhmTzM2dDc3S21wYW1FOTUrYTJkOWt6Yld3TUl3NQpSMERlKy95eHJDa3BRcTVma2lJQW9VMEIra1lGdmdmb1llMm9RUjBVSXN1SWNJcVNvQmtnUjlGQXYzdDBHV25iClZZa1VKOTlxQm5HT09OU1RLc09Ib29RemkrVnNJN0M3S1BvZTMzNkJaVnlWTTRHS1dJSnlNSTdPKysvUnFVK2YKa0FxQnVzcHBuZGxXREZsalZwNk5ydkhiZjRaaWxDbEluUVN0NHg3N0h6V0FSamo3Y3ZNb01nSEpEVXZJQS9NRwpIZEFYYjJ2N3VpZjhLTzFKK0Zza0tQdmVDdWNCeDhIUDlGTlIxNnZSSDVkZFBPK0xEU0xCMVNZZ3UrYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
server: https://127.0.0.1:6443
|
||||
name: default-cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: default-cluster
|
||||
namespace: default
|
||||
user: default-auth
|
||||
name: default-context
|
||||
current-context: default-context
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: default-auth
|
||||
user:
|
||||
client-certificate: ./one-cert.pem
|
||||
client-key: ./does-not-exist.pem
|
||||
@@ -1,17 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICyDCCAbCgAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
|
||||
cm5ldGVzMB4XDTE4MTIyNjEzMjczNFoXDTI4MTIyMzEzMjczNFowFTETMBEGA1UE
|
||||
AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPKX
|
||||
FJ3JQP1eKU/k3/Wk0yaKHD/Of5qWk2P31Uuiom6J9RS6MlNxWDFBerqzQisCH6j+
|
||||
a+s3xi3gfQueVqzT+PzTi5h3I+GpTgj9fu8zYy1mDb+toytjHus9E6EQxfqtHdTx
|
||||
3kdDJZeUbBeGMIyRGqLysOOPVupwQb701egQrXwmlLor2fiLPGAbyGAB0rcEbCZD
|
||||
hv305m6SEv7YOJN4oVL1LjYFNEvZBUqILR/KnCxcJspWkjPIOmB/UXILlLchIDhl
|
||||
CaZeioeb7ZPrcbZznjbHOciYiISI50J+61ywxz1g0JP2iftbfc0L/PYT6H9x1/xq
|
||||
4+W5AJWVeVyQIehfp6cCAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
|
||||
/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBALL8B5ljNHrpj4kI1/FAJfjh8Aku
|
||||
O7i2HKGdGgFrmGLyGZE3RDDCkr6PZQvUXBHfO36t77KmpamE95+a2d9kzbWwMIw5
|
||||
R0De+/yxrCkpQq5fkiIAoU0B+kYFvgfoYe2oQR0UIsuIcIqSoBkgR9FAv3t0GWnb
|
||||
VYkUJ99qBnGOONSTKsOHooQzi+VsI7C7KPoe336BZVyVM4GKWIJyMI7O++/RqU+f
|
||||
kAqBusppndlWDFljVp6NrvHbf4ZilClInQSt4x77HzWARjj7cvMoMgHJDUvIA/MG
|
||||
HdAXb2v7uif8KO1J+FskKPveCucBx8HP9FNR16vRH5ddPO+LDSLB1SYgu+c=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,4 +0,0 @@
|
||||
pyOpenSSL
|
||||
prometheus_client
|
||||
pyasn1
|
||||
PyYAML
|
||||
-271
@@ -1,271 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import base64
|
||||
import yaml
|
||||
|
||||
from OpenSSL import crypto
|
||||
|
||||
from prometheus_client import start_http_server
|
||||
from prometheus_client.core import GaugeMetricFamily, REGISTRY
|
||||
|
||||
from pyasn1.type.useful import GeneralizedTime
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""Return the parsed arguments."""
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
'-f',
|
||||
'--watch-file',
|
||||
action='append',
|
||||
metavar='FILE_PATH',
|
||||
help='one or more x509 certificate file')
|
||||
parser.add_argument(
|
||||
'-d',
|
||||
'--watch-dir',
|
||||
action='append',
|
||||
metavar='DIR_PATH',
|
||||
help='one or more directory which contains x509 certificate files')
|
||||
parser.add_argument(
|
||||
'-k',
|
||||
'--watch-kubeconf',
|
||||
action='append',
|
||||
metavar='KUBE_PATH',
|
||||
help='one or more Kubernetes client configuration (kind Config) which'
|
||||
' contains embedded x509 certificates or PEM file paths')
|
||||
parser.add_argument(
|
||||
'-p',
|
||||
'--port',
|
||||
default=9090,
|
||||
metavar='PORT',
|
||||
type=int,
|
||||
help='prometheus exporter listening port')
|
||||
|
||||
parser.add_argument(
|
||||
'--debug',
|
||||
action='store_true',
|
||||
help='enable debug mode')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def yaml_parser(fileobj):
|
||||
"""Returns a PyYAML parser avoiding warnings."""
|
||||
try:
|
||||
parser = yaml.load(fileobj, Loader=yaml.FullLoader)
|
||||
except AttributeError:
|
||||
parser = yaml.load(fileobj)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def parse_x509(filepath=None, b64=None, plain=None):
|
||||
"""x509 parsing helper."""
|
||||
if filepath:
|
||||
plain = open(filepath, 'rt').read()
|
||||
elif b64:
|
||||
plain = base64.b64decode(b64)
|
||||
|
||||
return crypto.load_certificate(crypto.FILETYPE_PEM, plain)
|
||||
|
||||
|
||||
def walk_x509_files_and_dirs(args):
|
||||
"""Compile a deduped list of files."""
|
||||
x509_filepaths = set([])
|
||||
if args.watch_file:
|
||||
for filename in args.watch_file:
|
||||
try:
|
||||
os.stat(filename)
|
||||
x509_filepaths.add(filename)
|
||||
except:
|
||||
logging.warning("not able to stat file: %s", filename)
|
||||
if args.watch_dir:
|
||||
for directory in args.watch_dir:
|
||||
for filename in os.listdir(directory):
|
||||
filepath = os.path.join(directory, filename)
|
||||
if os.path.isfile(filepath):
|
||||
x509_filepaths.add(filepath)
|
||||
return x509_filepaths
|
||||
|
||||
|
||||
def walk_kubeconf_files(args):
|
||||
"""Compile a deduped list of Kubernetes client configurations."""
|
||||
kubeconf_filepaths = set([])
|
||||
if args.watch_kubeconf:
|
||||
for filename in args.watch_kubeconf:
|
||||
try:
|
||||
with open(filename, 'r') as kubeconf:
|
||||
conf = yaml_parser(kubeconf)
|
||||
if conf['kind'] == 'Config' and conf['apiVersion'] == 'v1':
|
||||
kubeconf_filepaths.add(filename)
|
||||
except:
|
||||
logging.warning("not able to parse file: %s", filename)
|
||||
return kubeconf_filepaths
|
||||
|
||||
|
||||
def check_certificates(x509_filepaths):
|
||||
"""Verify file content and sanitize the filepaths."""
|
||||
valid_certificates = []
|
||||
for x509_filepath in x509_filepaths:
|
||||
try:
|
||||
parse_x509(filepath=x509_filepath)
|
||||
logging.info("valid x509 certificate detected: %s",
|
||||
x509_filepath)
|
||||
valid_certificates += [x509_filepath]
|
||||
except:
|
||||
logging.warning("not able to parse: %s", x509_filepath)
|
||||
return valid_certificates
|
||||
|
||||
|
||||
class X509Collector:
|
||||
"""a prometheus x509 collector."""
|
||||
|
||||
def __init__(self, x509_filepaths, kubeconf_filepaths):
|
||||
"""Take a set of filepaths as argument."""
|
||||
self.x509_filepaths = x509_filepaths
|
||||
self.kubeconf_filepaths = kubeconf_filepaths
|
||||
|
||||
def serialize_x509name(self, x509name):
|
||||
"""Helper to serialize a x509Name as a string."""
|
||||
return b' '.join(
|
||||
b'='.join(component) for component in x509name.get_components()
|
||||
).decode('utf-8')
|
||||
|
||||
def add_x509name_components_labels(self, x509name, labels, prefix):
|
||||
"""Add x509 name components to label list."""
|
||||
if x509name.C:
|
||||
labels[prefix + '_C'] = x509name.C
|
||||
if x509name.ST:
|
||||
labels[prefix + '_ST'] = x509name.ST
|
||||
if x509name.L:
|
||||
labels[prefix + '_L'] = x509name.L
|
||||
if x509name.O:
|
||||
labels[prefix + '_O'] = x509name.O
|
||||
if x509name.OU:
|
||||
labels[prefix + '_OU'] = x509name.OU
|
||||
if x509name.CN:
|
||||
labels[prefix + '_CN'] = x509name.CN
|
||||
|
||||
def build_labels(self, x509, filepath, embedded=None):
|
||||
"""Return prometheus metric labels."""
|
||||
labels = {
|
||||
'filename': os.path.basename(filepath),
|
||||
'filepath': filepath,
|
||||
'serial_number': "%s" % x509.get_serial_number(),
|
||||
}
|
||||
if embedded:
|
||||
labels.update(dict(zip(('embedded_kind', 'embedded_key'),
|
||||
embedded)))
|
||||
self.add_x509name_components_labels(
|
||||
x509.get_issuer(),
|
||||
labels, "issuer")
|
||||
self.add_x509name_components_labels(
|
||||
x509.get_subject(),
|
||||
labels, "subject")
|
||||
return labels
|
||||
|
||||
def build_metrics(self, x509):
|
||||
"""Return prometheus metrics."""
|
||||
x509_not_before_asn1_time = GeneralizedTime(x509.get_notBefore())
|
||||
x509_not_before_ts = x509_not_before_asn1_time.asDateTime.timestamp()
|
||||
|
||||
x509_not_after_asn1_time = GeneralizedTime(x509.get_notAfter())
|
||||
x509_not_after_ts = x509_not_after_asn1_time.asDateTime.timestamp()
|
||||
|
||||
expired = float(x509.has_expired())
|
||||
|
||||
return (x509_not_before_ts, x509_not_after_ts, expired)
|
||||
|
||||
def collect(self):
|
||||
"""The main Prometheus collector function."""
|
||||
kubex509_filepaths = []
|
||||
for kubeconf_filepath in self.kubeconf_filepaths:
|
||||
try:
|
||||
with open(kubeconf_filepath, 'r') as kubeconf:
|
||||
conf = yaml_parser(kubeconf)
|
||||
cert_roots = [('cluster', 'certificate-authority'),
|
||||
('user', 'client-certificate')]
|
||||
for item_type, key_base in cert_roots:
|
||||
for item in conf.get("{}s".format(item_type), []):
|
||||
name = item.get("name")
|
||||
item_data = item.get(item_type)
|
||||
if not name or not item_data:
|
||||
continue
|
||||
|
||||
if key_base in item_data:
|
||||
kubex509_filepaths.append(item_data.get(key_base))
|
||||
|
||||
mbed_key = "{}-data".format(key_base)
|
||||
if mbed_key in item_data:
|
||||
x509 = parse_x509(b64=item_data.get(mbed_key))
|
||||
labels = self.build_labels(x509, kubeconf_filepath,
|
||||
embedded=(item_type, name))
|
||||
yield from self.emit_x509(x509, labels)
|
||||
except:
|
||||
logging.warning("not able to parse and compute: %s",
|
||||
kubeconf_filepath)
|
||||
|
||||
for x509_filepath in self.x509_filepaths + kubex509_filepaths:
|
||||
try:
|
||||
x509 = parse_x509(filepath=x509_filepath)
|
||||
yield from self.emit_x509(x509,
|
||||
self.build_labels(x509, x509_filepath))
|
||||
except:
|
||||
logging.warning("not able to parse and compute: %s",
|
||||
x509_filepath)
|
||||
|
||||
def emit_x509(self, x509, labels):
|
||||
"""Produce Prometheus metrics."""
|
||||
not_before, not_after, expired = self.build_metrics(x509)
|
||||
|
||||
metric = GaugeMetricFamily(
|
||||
'x509_cert_not_before',
|
||||
"x509 certificate not_before timestamp",
|
||||
labels=labels.keys())
|
||||
metric.add_metric(labels.values(), not_before)
|
||||
yield metric
|
||||
|
||||
metric = GaugeMetricFamily(
|
||||
'x509_cert_not_after',
|
||||
"x509 certificate not_after timestamp",
|
||||
labels=labels.keys())
|
||||
metric.add_metric(labels.values(), not_after)
|
||||
yield metric
|
||||
|
||||
metric = GaugeMetricFamily(
|
||||
'x509_cert_expired',
|
||||
"x509 certificate expiration boolean",
|
||||
labels=labels.keys())
|
||||
metric.add_metric(labels.values(), expired)
|
||||
yield metric
|
||||
|
||||
|
||||
LOOP_SLEEP_TIME = 300
|
||||
|
||||
|
||||
def main():
|
||||
"""x509-exporter main function."""
|
||||
args = parse_args()
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG if args.debug else logging.INFO,
|
||||
format='%(asctime)s %(levelname)s %(message)s')
|
||||
|
||||
x509_filepaths = walk_x509_files_and_dirs(args)
|
||||
x509_filepaths = check_certificates(x509_filepaths)
|
||||
kubeconfig_filepaths = walk_kubeconf_files(args)
|
||||
logging.info("monitoring %s certificate(s) and %s kubeconfig(s)",
|
||||
len(x509_filepaths), len(kubeconfig_filepaths))
|
||||
REGISTRY.register(X509Collector(x509_filepaths, kubeconfig_filepaths))
|
||||
logging.info("starting exporter on port %d", args.port)
|
||||
start_http_server(args.port)
|
||||
while True:
|
||||
time.sleep(LOOP_SLEEP_TIME)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user