certs

package module
v0.18.3 Latest Latest
Warning

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

Go to latest
Published: Nov 28, 2025 License: Apache-2.0 Imports: 21 Imported by: 1

README

Abstract Machines Certificate Manager

codecov license

Abstract Machines Certicate Manager is an open source, lightweight, scalable, and customizable certs manager. This PKI (Public Key Infrastructure) service provides a comprehensive set of features for managing digital certificates. It includes an SDK, CLI, and API that enable the following functionality:

  • Certificate Issuance: Issue new certificates for entities, specifying parameters like the certificate type, TTL, IP addresses, and subject options.
  • Certificate Renewal: Renew existing certificates in the database.
  • Certificate Revocation: Revoke certificates that are no longer valid or trusted.
  • Certificate Retrieval: Retrieve certificate records from the database, including options to view, download, and get OCSP responses.
  • Certificate Listing: List certificates based on various filters, such as entity ID, expiry time, and revocation status.
  • Certificate Authority (CA) Management: Retrieve the chain of CA certificates (root and intermediate) and generate Certificate Revocation Lists (CRLs).

Features

  • PKI (Certificate renewal)
  • Active revocation (CRL, OSCP)
  • API (For management of PKI)
  • SDK
  • CLI

Prerequisites

The following are needed to run absmach certs:

Developing absmach certs will also require:

Install

Once the prerequisites are installed, clone the repo

git clone https://github.com/absmach/certs.git
cd certs

Execute the following commands from the project's root:

docker compose -f docker/docker-compose.yaml --env-file docker/.env -p absmach up

This will bring up the certs docker services and interconnect them. This command can also be executed using the project's included Makefile:

make run

Usage

SDK

Absmach certs provides an SDK that can be imported and used in your Go applications. Here's an example of how to use the SDK:

cert , _ := sdk.IssueCert("entityID", "10h", []string{"ipAddr1", "ipAddr2"}, sdk.Options{CommonName: "commonName"})
fmt.Println(cert)
CLI

Absmach certs also provides a command-line interface (CLI) for interacting with the service. The CLI supports the following commands:

  • issue: Issue a new certificate
  • get: List certificates
  • token: Gets download token
  • download: Downloads a certificate
  • renew: Renew an existing certificate
  • revoke: Revoke a certificate
  • view: Retrieve a certificate
  • generate-crl: Generate a Certificate Revocation List (CRL)
  • token-ca: Gets CA download token
  • download-ca: Retrieve the chain of CA certificates
API

The absmach certs exposes a RESTful API that can be used to interact with the service programmatically. Here is an example using cURL:

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"ip_addresses":["191.168.101.16"],"ttl":"10h","options":{"organization":["organization_name"]}}' \
  http://localhost:9010/certs/issue/64eeb24e-6154-48c4-ad32-e4fb02ed32da\?common_name\=thing

Contributing

Thank you for your interest in Absmach certs and the desire to contribute!

  1. Take a look at our open issues.
  2. Checkout the contribution guide to learn more about our style and conventions.
  3. Make your changes compatible to our workflow.

Also, explore our contrib repository for extra services such as Cassandra, InfluxDB, MongoDB readers and writers, LoRa, OPC UA support, Digital Twins, and more. If you have a contribution that is not a good fit for the core monorepo (it's specific to your use case, it's an additional feature or a new service, it's optional or an add-on), this is a great place to submit the pull request.

Community

License

Apache-2.0

Documentation

Index

Constants

View Source
const (
	Root    = "RootCA"
	Inter   = "IntermediateCA"
	Client  = "ClientCert"
	Unknown = "Unknown"
)
View Source
const (
	CertsService_GetEntityID_FullMethodName = "/absmach.certs.CertsService/GetEntityID"
	CertsService_RevokeCerts_FullMethodName = "/absmach.certs.CertsService/RevokeCerts"
)
View Source
const (
	PrivateKeyBytes              = 2048
	RootCAValidityPeriod         = time.Hour * 24 * 365 // 365 days
	IntermediateCAValidityPeriod = time.Hour * 24 * 90  // 90 days

	PrivateKey      = "PRIVATE KEY"
	RSAPrivateKey   = "RSA PRIVATE KEY"
	ECPrivateKey    = "EC PRIVATE KEY"
	PKCS8PrivateKey = "PKCS8 PRIVATE KEY"
	EDPrivateKey    = "ED25519 PRIVATE KEY"
)

Variables

View Source
var (
	// Version represents the last service git tag in git history.
	// It's meant to be set using go build ldflags.
	Version = "0.0.0"

	Commit = "ffffffff"
	// BuildTime represetns the service build time.
	// It's meant to be set using go build ldflags.
	BuildTime = "1970-01-01_00:00:00"
)
View Source
var (
	ErrNotFound               = errors.New("entity not found")
	ErrConflict               = errors.New("entity already exists")
	ErrCreateEntity           = errors.New("failed to create entity")
	ErrViewEntity             = errors.New("view entity failed")
	ErrUpdateEntity           = errors.New("update entity failed")
	ErrDeleteEntity           = errors.New("delete entity failed")
	ErrMalformedEntity        = errors.New("malformed entity specification")
	ErrRootCANotFound         = errors.New("root CA not found")
	ErrIntermediateCANotFound = errors.New("intermediate CA not found")
	ErrCertExpired            = errors.New("certificate expired before renewal")
	ErrCertRevoked            = errors.New("certificate has been revoked and cannot be renewed")
	ErrCertInvalidType        = errors.New("invalid cert type")
	ErrInvalidLength          = errors.New("invalid length of serial numbers")
	ErrPrivKeyType            = errors.New("unsupported private key type")
	ErrPubKeyType             = errors.New("unsupported public key type")
	ErrFailedParse            = errors.New("failed to parse key PEM")
	ErrFailedCertCreation     = errors.New("failed to create certificate")
	ErrInvalidIP              = errors.New("invalid IP address")
)
View Source
var CertsService_ServiceDesc = grpc.ServiceDesc{
	ServiceName: "absmach.certs.CertsService",
	HandlerType: (*CertsServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "GetEntityID",
			Handler:    _CertsService_GetEntityID_Handler,
		},
		{
			MethodName: "RevokeCerts",
			Handler:    _CertsService_RevokeCerts_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "certs.proto",
}

CertsService_ServiceDesc is the grpc.ServiceDesc for CertsService service. It's only intended for direct use with grpc.RegisterService, and not to be introspected or modified (even as a copy)

View Source
var File_certs_proto protoreflect.FileDescriptor

Functions

func Health

func Health(service, instanceID string) http.HandlerFunc

Health exposes an HTTP handler for retrieving service health.

func RegisterCertsServiceServer

func RegisterCertsServiceServer(s grpc.ServiceRegistrar, srv CertsServiceServer)

Types

type Agent added in v0.18.0

type Agent interface {
	Issue(ttl string, ipAddrs []string, options SubjectOptions) (Certificate, error)
	View(serialNumber string) (Certificate, error)
	Revoke(serialNumber string) error
	ListCerts(pm PageMetadata) (CertificatePage, error)
	GetCA() ([]byte, error)
	GetCAChain() ([]byte, error)
	GetCRL() ([]byte, error)
	SignCSR(csr []byte, ttl string) (Certificate, error)
	Renew(cert Certificate, increment string) (Certificate, error)
	OCSP(serialNumber string, ocspRequestDER []byte) ([]byte, error)
}

Agent represents the PKI interface that all PKI implementations must satisfy.

type CA

type CA struct {
	Type         CertType
	Certificate  *x509.Certificate
	PrivateKey   *rsa.PrivateKey
	SerialNumber string
}

type CSR

type CSR struct {
	CSR        []byte `json:"csr,omitempty"`
	PrivateKey []byte `json:"private_key,omitempty"`
}

type CSRMetadata

type CSRMetadata struct {
	CommonName         string           `json:"common_name"`
	Organization       []string         `json:"organization"`
	OrganizationalUnit []string         `json:"organizational_unit"`
	Country            []string         `json:"country"`
	Province           []string         `json:"province"`
	Locality           []string         `json:"locality"`
	StreetAddress      []string         `json:"street_address"`
	PostalCode         []string         `json:"postal_code"`
	DNSNames           []string         `json:"dns_names"`
	IPAddresses        []string         `json:"ip_addresses"`
	EmailAddresses     []string         `json:"email_addresses"`
	ExtraExtensions    []pkix.Extension `json:"extra_extensions"`
}

type CSRPage

type CSRPage struct {
	PageMetadata
	CSRs []CSR `json:"csrs,omitempty"`
}

type CertType

type CertType int
const (
	RootCA CertType = iota
	IntermediateCA
	ClientCert
)

func CertTypeFromString

func CertTypeFromString(s string) (CertType, error)

func (CertType) String

func (c CertType) String() string

type Certificate

type Certificate struct {
	SerialNumber string    `json:"serial_number"`
	Certificate  []byte    `json:"certificate"`
	Key          []byte    `json:"key"`
	Revoked      bool      `json:"revoked"`
	ExpiryTime   time.Time `json:"expiry_time"`
	EntityID     string    `json:"entity_id"`
	Type         CertType  `json:"type"`
	DownloadUrl  string    `json:"-"`
}

type CertificatePage

type CertificatePage struct {
	PageMetadata
	Certificates []Certificate
}

type CertsServiceClient

type CertsServiceClient interface {
	GetEntityID(ctx context.Context, in *EntityReq, opts ...grpc.CallOption) (*EntityRes, error)
	RevokeCerts(ctx context.Context, in *RevokeReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
}

CertsServiceClient is the client API for CertsService service.

For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.

type CertsServiceServer

type CertsServiceServer interface {
	GetEntityID(context.Context, *EntityReq) (*EntityRes, error)
	RevokeCerts(context.Context, *RevokeReq) (*emptypb.Empty, error)
	// contains filtered or unexported methods
}

CertsServiceServer is the server API for CertsService service. All implementations must embed UnimplementedCertsServiceServer for forward compatibility.

type EntityReq

type EntityReq struct {
	SerialNumber string `protobuf:"bytes,1,opt,name=serial_number,json=serialNumber,proto3" json:"serial_number,omitempty"`
	// contains filtered or unexported fields
}

func (*EntityReq) Descriptor deprecated

func (*EntityReq) Descriptor() ([]byte, []int)

Deprecated: Use EntityReq.ProtoReflect.Descriptor instead.

func (*EntityReq) GetSerialNumber

func (x *EntityReq) GetSerialNumber() string

func (*EntityReq) ProtoMessage

func (*EntityReq) ProtoMessage()

func (*EntityReq) ProtoReflect

func (x *EntityReq) ProtoReflect() protoreflect.Message

func (*EntityReq) Reset

func (x *EntityReq) Reset()

func (*EntityReq) String

func (x *EntityReq) String() string

type EntityRes

type EntityRes struct {
	EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
	// contains filtered or unexported fields
}

func (*EntityRes) Descriptor deprecated

func (*EntityRes) Descriptor() ([]byte, []int)

Deprecated: Use EntityRes.ProtoReflect.Descriptor instead.

func (*EntityRes) GetEntityId

func (x *EntityRes) GetEntityId() string

func (*EntityRes) ProtoMessage

func (*EntityRes) ProtoMessage()

func (*EntityRes) ProtoReflect

func (x *EntityRes) ProtoReflect() protoreflect.Message

func (*EntityRes) Reset

func (x *EntityRes) Reset()

func (*EntityRes) String

func (x *EntityRes) String() string

type HealthInfo

type HealthInfo struct {
	// Status contains service status.
	Status string `json:"status"`

	// Version contains current service version.
	Version string `json:"version"`

	// Commit represents the git hash commit.
	Commit string `json:"commit"`

	// Description contains service description.
	Description string `json:"description"`

	// BuildTime contains service build time.
	BuildTime string `json:"build_time"`

	// InstanceID contains the ID of the current service instance
	InstanceID string `json:"instance_id"`
}

HealthInfo contains version endpoint response.

type PageMetadata

type PageMetadata struct {
	Total    uint64 `json:"total"`
	Offset   uint64 `json:"offset,omitempty"`
	Limit    uint64 `json:"limit,omitempty"`
	EntityID string `json:"entity_id,omitempty"`
}

type Repository

type Repository interface {
	// SaveCertEntityMapping saves the mapping between certificate serial number and entity ID.
	SaveCertEntityMapping(ctx context.Context, serialNumber, entityID string) error

	// GetEntityIDBySerial retrieves the entity ID for a given certificate serial number.
	GetEntityIDBySerial(ctx context.Context, serialNumber string) (string, error)

	// ListCertsByEntityID lists all certificate serial numbers for a given entity ID.
	ListCertsByEntityID(ctx context.Context, entityID string) ([]string, error)

	// RemoveCertEntityMapping removes the mapping between certificate and entity ID.
	RemoveCertEntityMapping(ctx context.Context, serialNumber string) error
}

type RevokeReq

type RevokeReq struct {
	EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
	// contains filtered or unexported fields
}

func (*RevokeReq) Descriptor deprecated

func (*RevokeReq) Descriptor() ([]byte, []int)

Deprecated: Use RevokeReq.ProtoReflect.Descriptor instead.

func (*RevokeReq) GetEntityId

func (x *RevokeReq) GetEntityId() string

func (*RevokeReq) ProtoMessage

func (*RevokeReq) ProtoMessage()

func (*RevokeReq) ProtoReflect

func (x *RevokeReq) ProtoReflect() protoreflect.Message

func (*RevokeReq) Reset

func (x *RevokeReq) Reset()

func (*RevokeReq) String

func (x *RevokeReq) String() string

type Service

type Service interface {
	// RenewCert renews a certificate by issuing a new certificate with the same parameters.
	// Returns the new certificate with extended TTL and a new serial number.
	RenewCert(ctx context.Context, session authn.Session, serialNumber string) (Certificate, error)

	// RevokeBySerial revokes a single certificate by its serial number.
	RevokeBySerial(ctx context.Context, session authn.Session, serialNumber string) error

	// RevokeAll revokes all certificates for a given entity ID.
	RevokeAll(ctx context.Context, session authn.Session, entityID string) error

	// ViewCert retrieves a certificate record from the database.
	ViewCert(ctx context.Context, session authn.Session, serialNumber string) (Certificate, error)

	// ListCerts retrieves the certificates from the database while applying filters.
	ListCerts(ctx context.Context, session authn.Session, pm PageMetadata) (CertificatePage, error)

	// IssueCert issues a certificate from the database.
	IssueCert(ctx context.Context, session authn.Session, entityID, ttl string, ipAddrs []string, option SubjectOptions) (Certificate, error)

	// OCSP forwards OCSP requests to OpenBao's OCSP endpoint.
	// If ocspRequestDER is provided, it will be used directly; otherwise, a request will be built from the serialNumber.
	OCSP(ctx context.Context, serialNumber string, ocspRequestDER []byte) ([]byte, error)

	// GetEntityID retrieves the entity ID for a certificate.
	GetEntityID(ctx context.Context, serialNumber string) (string, error)

	// GenerateCRL creates cert revocation list.
	GenerateCRL(ctx context.Context) ([]byte, error)

	// RetrieveCAChain retrieves the chain of CA i.e. root and intermediate cert concat together.
	RetrieveCAChain(ctx context.Context) (Certificate, error)

	// IssueFromCSR creates a certificate from a given CSR.
	IssueFromCSR(ctx context.Context, session authn.Session, entityID, ttl string, csr CSR) (Certificate, error)

	// IssueFromCSRInternal creates a certificate from a given CSR using agent token authentication.
	IssueFromCSRInternal(ctx context.Context, entityID, ttl string, csr CSR) (Certificate, error)
}

func NewService

func NewService(ctx context.Context, pki Agent, repo Repository) (Service, error)

type SubjectOptions

type SubjectOptions struct {
	CommonName         string   `json:"common_name"`
	Organization       []string `json:"organization"`
	OrganizationalUnit []string `json:"organizational_unit"`
	Country            []string `json:"country"`
	Province           []string `json:"province"`
	Locality           []string `json:"locality"`
	StreetAddress      []string `json:"street_address"`
	PostalCode         []string `json:"postal_code"`
	DnsNames           []string `json:"dns_names"`
	IpAddresses        []net.IP `json:"ip_addresses"`
}

type UnimplementedCertsServiceServer

type UnimplementedCertsServiceServer struct{}

UnimplementedCertsServiceServer must be embedded to have forward compatible implementations.

NOTE: this should be embedded by value instead of pointer to avoid a nil pointer dereference when methods are called.

func (UnimplementedCertsServiceServer) GetEntityID

func (UnimplementedCertsServiceServer) RevokeCerts

type UnsafeCertsServiceServer

type UnsafeCertsServiceServer interface {
	// contains filtered or unexported methods
}

UnsafeCertsServiceServer may be embedded to opt out of forward compatibility for this service. Use of this interface is not recommended, as added methods to CertsServiceServer will result in compilation errors.

Directories

Path Synopsis
api
cmd
certs command
cli command
Package main contains cli main function to run the cli.
Package main contains cli main function to run the cli.
Package pki wraps OpenBao client for PKI operations
Package pki wraps OpenBao client for PKI operations
sdk

Jump to

Keyboard shortcuts

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