certs

package
v0.40.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

Certs Service

The Certs service issues and manages X.509 certificates for IoT things, enabling mutual TLS (mTLS) authentication between devices and the platform. Certificates are signed by a local CA and identified by their serial number. Each certificate records the associated thing ID in the subject, making it straightforward to trace a TLS connection back to a specific device.

Certificates

Field Description
serial Certificate serial number (hex string); used as the unique identifier
thing_id ID of the thing the certificate was issued for
certificate PEM-encoded X.509 certificate
issuing_ca PEM-encoded certificate of the issuing CA
ca_chain Full CA certificate chain in PEM format
private_key PEM-encoded private key corresponding to the certificate
private_key_type Key algorithm: rsa or ec
expires_at Certificate expiration timestamp (RFC 3339)

Configuration

The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.

Variable Description Default
MF_CERTS_LOG_LEVEL Log level for the Certs service (debug, info, warn, error) error
MF_CERTS_HTTP_PORT Certs service HTTP port 8204
MF_JAEGER_URL Jaeger server URL for distributed tracing. Leave empty to disable tracing.
MF_CERTS_DB_HOST Database host address localhost
MF_CERTS_DB_PORT Database host port 5432
MF_CERTS_DB_USER Database user mainflux
MF_CERTS_DB_PASS Database password mainflux
MF_CERTS_DB Name of the database used by the service certs
MF_CERTS_DB_SSL_MODE Database connection SSL mode (disable, require, verify-ca, verify-full) disable
MF_CERTS_DB_SSL_CERT Path to the PEM encoded certificate file
MF_CERTS_DB_SSL_KEY Path to the PEM encoded key file
MF_CERTS_DB_SSL_ROOT_CERT Path to the PEM encoded root certificate file
MF_CERTS_CLIENT_TLS Flag that indicates if TLS should be turned on false
MF_CERTS_CA_CERTS Path to trusted CAs in PEM format
MF_CERTS_SERVER_CERT Path to server certificate in PEM format
MF_CERTS_SERVER_KEY Path to server key in PEM format
MF_CERTS_SIGN_CA_PATH Path to the CA certificate used for signing ca.crt
MF_CERTS_SIGN_CA_KEY_PATH Path to the CA private key used for signing ca.key
MF_CERTS_SIGN_HOURS_VALID Default certificate validity period (Go duration string) 2048h
MF_CERTS_SIGN_RSA_BITS RSA key size used when not specified in the request 2048
MF_AUTH_GRPC_URL Auth service gRPC URL localhost:8181
MF_AUTH_GRPC_TIMEOUT Auth service gRPC request timeout 1s
MF_THINGS_GRPC_URL Things service gRPC URL (used to verify thing ownership) localhost:8183
MF_THINGS_GRPC_TIMEOUT Things service gRPC request timeout 1s
MF_SDK_CERTS_URL Base URL of the Certs service, used by the SDK client http://localhost

Deployment

The service itself is distributed as Docker container. Check the certs service section in docker-compose to see how service is deployed.

To start the service, execute the following shell script:

# Download the latest version of the service
git clone https://github.com/MainfluxLabs/mainflux

cd mainflux

# Compile the certs service
make certs

# Copy binary to bin
make install

# Set the environment variables and run the service
MF_CERTS_LOG_LEVEL=[Certs log level] \
MF_CERTS_HTTP_PORT=[Certs service HTTP port] \
MF_CERTS_DB_HOST=[Database host address] \
MF_CERTS_DB_PORT=[Database host port] \
MF_CERTS_DB_USER=[Database user] \
MF_CERTS_DB_PASS=[Database password] \
MF_CERTS_DB=[Name of the database used by the service] \
MF_CERTS_SIGN_CA_PATH=[Path to CA certificate] \
MF_CERTS_SIGN_CA_KEY_PATH=[Path to CA private key] \
MF_CERTS_SIGN_HOURS_VALID=[Certificate validity period] \
MF_AUTH_GRPC_URL=[Auth service gRPC URL] \
$GOBIN/mainfluxlabs-certs

Usage

First, obtain an authentication token:

TOK=$(curl -s -X POST http://localhost/tokens \
  -H 'Content-Type: application/json' \
  -d '{"email":"user@example.com","password":"12345678"}' | jq -r '.token')
Issue a certificate
curl -s -X POST http://localhost:8204/certs \
  -H "Authorization: Bearer $TOK" \
  -H 'Content-Type: application/json' \
  -d '{"thing_id":"<thing_id>","key_bits":2048,"key_type":"rsa"}'

Supported key types: rsa (default), ec.

List certificates for a thing
curl -s "http://localhost/svccerts/things/<thing_id>/serials" \
  -H "Authorization: Bearer $TOK"
View a certificate
curl -s http://localhost:8204/certs/<serial> \
  -H "Authorization: Bearer $TOK"
Renew a certificate

A certificate can only be renewed when it is within 30 days of its expiration date. Attempting to renew earlier returns an error. Renewal issues a new certificate with a fresh serial and extended validity; the old certificate is revoked.

curl -s -X PUT http://localhost:8204/certs/<serial> \
  -H "Authorization: Bearer $TOK"
Revoke a certificate
curl -s -X DELETE http://localhost:8204/certs/<serial> \
  -H "Authorization: Bearer $TOK"

For the full HTTP API reference, see the OpenAPI specification.

Documentation

Overview

Package certs contains the domain concept definitions needed to support Mainflux certs service functionality.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrFailedCertCreation failed to create certificate
	ErrFailedCertCreation = errors.New("failed to create client certificate")

	// ErrFailedCertRevocation failed to revoke certificate
	ErrFailedCertRevocation = errors.New("failed to revoke certificate")

	// ErrNotEligibleForRenewal indicates the certificate cannot be renewed yet because it expires more than 30 days from now.
	ErrNotEligibleForRenewal = errors.New("certificate not eligible for renewal yet")

	// ErrCertAlreadyDownloaded indicates the certificate has already been downloaded.
	ErrCertAlreadyDownloaded = errors.New("certificate already downloaded")
)

Functions

func GenerateCRLFile added in v0.40.0

func GenerateCRLFile(ctx context.Context, repo Repository, pkiAgent pki.Agent, crlPath string) error

GenerateCRLFile generates a PEM-encoded CRL file from the current revoked certificates and writes it to the given path. It is used both at startup and after each revocation.

Types

type Cert

type Cert struct {
	ThingID        string    `json:"thing_id" mapstructure:"thing_id"`
	ClientCert     string    `json:"client_cert" mapstructure:"certificate"`
	IssuingCA      string    `json:"issuing_ca" mapstructure:"issuing_ca"`
	CAChain        []string  `json:"ca_chain" mapstructure:"ca_chain"`
	ClientKey      string    `json:"client_key" mapstructure:"private_key"`
	PrivateKeyType string    `json:"private_key_type" mapstructure:"private_key_type"`
	KeyBits        int       `json:"key_bits" mapstructure:"key_bits"`
	Serial         string    `json:"serial" mapstructure:"serial_number"`
	ExpiresAt      time.Time `json:"expires_at" mapstructure:"-"`
	Downloaded     bool      `json:"downloaded" mapstructure:"downloaded"`
}

Cert defines the certificate parameters

type CertEvent added in v0.40.0

type CertEvent struct {
	ThingID    string   `json:"thing_id"`
	ClientCert string   `json:"client_cert"`
	ClientKey  string   `json:"client_key"`
	IssuingCA  string   `json:"issuing_ca"`
	CAChain    []string `json:"ca_chain"`
	Serial     string   `json:"serial"`
	ExpiresAt  string   `json:"expires_at"`
}

CertEvent is the payload published to the message bus when a certificate is rotated.

type CertScheduler added in v0.40.0

type CertScheduler struct {
	// contains filtered or unexported fields
}

CertScheduler periodically renews certificates approaching expiration and notifies Things of their new credentials via the message bus.

func NewCertScheduler added in v0.40.0

func NewCertScheduler(repo Repository, pkiAgent pki.Agent, things domain.ThingsClient, pub messaging.Publisher, crlPath string, logger logger.Logger) *CertScheduler

NewCertScheduler creates a new certificate rotation scheduler.

func (*CertScheduler) Start added in v0.40.0

func (cs *CertScheduler) Start(ctx context.Context, schedule mfcron.Scheduler) error

Start registers the rotation task with the cron scheduler and blocks until context is cancelled.

type Config

type Config struct {
	LogLevel       string
	ClientTLS      bool
	CaCerts        string
	HTTPPort       string
	ServerCert     string
	ServerKey      string
	CertsURL       string
	JaegerURL      string
	AuthURL        string
	AuthTimeout    time.Duration
	SignTLSCert    tls.Certificate
	SignX509Cert   *x509.Certificate
	SignRSABits    int
	SignHoursValid string
	CRLPath        string
}

Config defines the service parameters

type Page

type Page struct {
	Total uint64
	Certs []Cert
}

ConfigsPage contains page related metadata as well as list

type Repository

type Repository interface {
	// Save  saves cert for thing into database
	Save(ctx context.Context, cert Cert) (string, error)

	// RetrieveAll retrieve issued certificates
	RetrieveAll(ctx context.Context, offset, limit uint64) (Page, error)

	// Remove removes certificate from DB for a given serial
	Remove(ctx context.Context, serial string) error

	// RetrieveByThing retrieves issued certificates for a given thing ID
	RetrieveByThing(ctx context.Context, thingID string, offset, limit uint64) (Page, error)

	// RetrieveBySerial retrieves a certificate for a given serial
	RetrieveBySerial(ctx context.Context, serial string) (Cert, error)

	// RetrieveExpiring retrieves certificates that expire within the given duration.
	RetrieveExpiring(ctx context.Context, expiresWithin time.Duration) ([]Cert, error)

	// RetrieveRevokedCerts retrieves all revoked certificates
	RetrieveRevokedCerts(ctx context.Context) ([]RevokedCert, error)

	// MarkDownloaded marks a certificate as downloaded
	MarkDownloaded(ctx context.Context, serial string) error
}

Repository specifies a Config persistence API.

type Revoke

type Revoke struct {
	RevocationTime time.Time `mapstructure:"revocation_time"`
}

Revoke defines the conditions to revoke a certificate

type RevokedCert added in v0.32.1

type RevokedCert struct {
	Serial    string    `db:"serial"`
	ThingID   string    `db:"thing_id"`
	RevokedAt time.Time `db:"revoked_at"`
}

type Service

type Service interface {
	// IssueCert issues certificate for given thing id if access is granted with token.
	IssueCert(ctx context.Context, token, thingID, ttl string, keyBits int, keyType string) (Cert, error)

	// RotateCert rotates the certificate by revoking the cert with given serial and issuing a new one.
	RotateCert(ctx context.Context, token, serial, thingID, ttl string, keyBits int, keyType string) (Cert, error)

	// ListCerts lists certificates issued for a given thing ID.
	ListCerts(ctx context.Context, token, thingID string, offset, limit uint64) (Page, error)

	// ListSerials lists certificate serial numbers issued for a given thing ID.
	ListSerials(ctx context.Context, token, thingID string, offset, limit uint64) (Page, error)

	// ViewCert retrieves the certificate issued for a given serial ID.
	ViewCert(ctx context.Context, token, serial string) (Cert, error)

	// RevokeCert revokes a certificate for a given serial ID.
	RevokeCert(ctx context.Context, token, serial string) (Revoke, error)

	// RenewCert extends the expiration date of a certificate.
	RenewCert(ctx context.Context, token, serial string) (Cert, error)

	// DownloadCert retrieves the full certificate data (key, cert, CA) and marks it as downloaded.
	// Authenticates via thingKey (device self-provisioning); serial must belong to the thing.
	DownloadCert(ctx context.Context, thingKey domain.ThingKey, serial string) (Cert, error)
}

Service specifies an API that must be fulfilled by the domain service implementation, and all of its decorators (e.g. logging & metrics).

func New

func New(auth domain.AuthClient, things domain.ThingsClient, certs Repository, config Config, pkiAgent pki.Agent) Service

New returns new Certs service.

Directories

Path Synopsis
Package api contains implementation of certs service HTTP API.
Package api contains implementation of certs service HTTP API.
Package postgres contains repository implementations using PostgreSQL as the underlying database.
Package postgres contains repository implementations using PostgreSQL as the underlying database.
Package tracing contains middlewares that will add spans to existing traces.
Package tracing contains middlewares that will add spans to existing traces.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL