Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions api/v1alpha1/bmc_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ const (
ProtocolRedfishLocal = "RedfishLocal"
// ProtocolRedfishKube is the RedfishKube protocol.
ProtocolRedfishKube = "RedfishKube"

// BMCCertificateReadyCondition indicates that the BMC certificate is ready.
BMCCertificateReadyCondition = "CertificateReady"

// BMCCertificateReadyReasonIssued indicates that the certificate was successfully issued.
BMCCertificateReadyReasonIssued = "Issued"
// BMCCertificateReadyReasonPending indicates that the certificate request is pending.
BMCCertificateReadyReasonPending = "Pending"
// BMCCertificateReadyReasonFailed indicates that the certificate request failed.
BMCCertificateReadyReasonFailed = "Failed"
)

// BMCSpec defines the desired state of BMC
Expand Down Expand Up @@ -61,6 +71,53 @@ type BMCSpec struct {
// Hostname is the hostname of the BMC.
// +optional
Hostname *string `json:"hostname,omitempty"`

// Certificate specifies the certificate configuration for the BMC.
// +optional
Certificate *BMCCertificateSpec `json:"certificate,omitempty"`
}

// BMCCertificateSpec defines the desired certificate configuration for a BMC.
type BMCCertificateSpec struct {
// IssuerRef is a reference to the cert-manager Issuer or ClusterIssuer.
// +required
IssuerRef CertificateIssuerRef `json:"issuerRef"`

// Duration is the requested duration for the certificate.
// +optional
Duration *metav1.Duration `json:"duration,omitempty"`

// CommonName is the common name to be used on the certificate.
// +optional
CommonName string `json:"commonName,omitempty"`

// DNSNames is a list of DNS names to be used on the certificate.
// +optional
DNSNames []string `json:"dnsNames,omitempty"`

// IPAddresses is a list of IP addresses to be used on the certificate.
// +optional
IPAddresses []string `json:"ipAddresses,omitempty"`
}

// CertificateIssuerRef defines a reference to a cert-manager Issuer or ClusterIssuer.
type CertificateIssuerRef struct {
// Name is the name of the Issuer or ClusterIssuer.
// +required
Name string `json:"name"`

// Kind is the type of the issuer (Issuer or ClusterIssuer).
// +kubebuilder:validation:Enum=Issuer;ClusterIssuer
// +kubebuilder:default=Issuer
// +optional
Kind string `json:"kind,omitempty"`

// Group is the API group of the Issuer or ClusterIssuer.
// Defaults to cert-manager.io if not specified.
// This field allows referencing issuers from external cert-manager implementations.
// +kubebuilder:default=cert-manager.io
// +optional
Group string `json:"group,omitempty"`
Comment on lines +103 to +120
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Issuer refs are ambiguous on a cluster-scoped BMC.

Because BMC is cluster-scoped, this type has no way to identify which namespace a namespaced Issuer should come from, yet Kind defaults to Issuer. That forces the controller to resolve namespaced issuers from an implicit namespace, which is surprising and impossible to override per BMC. Either add a namespace field/validation for Kind=Issuer, or restrict this API to ClusterIssuer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v1alpha1/bmc_types.go` around lines 103 - 120, CertificateIssuerRef is
ambiguous for cluster-scoped BMC because Kind defaults to "Issuer" but there's
no namespace to locate a namespaced Issuer; update the type to either require
namespace when Kind=="Issuer" or restrict Kind to ClusterIssuer—prefer adding an
optional Namespace string `Namespace string json:"namespace,omitempty"` to
CertificateIssuerRef and add kubebuilder validation so Namespace is required
when Kind==Issuer (or alternatively change the default/Enum to only
ClusterIssuer if you choose to disallow Issuer); update the doc comment for
CertificateIssuerRef and the kubebuilder markers on Kind to reflect the chosen
behavior so the controller can deterministically resolve issuers.

}

// InlineEndpoint defines inline network access configuration for the BMC.
Expand Down Expand Up @@ -214,6 +271,14 @@ type BMCStatus struct {
// +optional
EventsSubscriptionLink string `json:"eventsSubscriptionLink,omitempty"`

// CertificateSecretRef is a reference to the secret containing the BMC certificate.
// +optional
CertificateSecretRef *v1.LocalObjectReference `json:"certificateSecretRef,omitempty"`

// CertificateRequestName is the name of the cert-manager CertificateRequest.
// +optional
CertificateRequestName string `json:"certificateRequestName,omitempty"`

// Conditions represents the latest available observations of the BMC's current state.
// +patchStrategy=merge
// +patchMergeKey=type
Expand Down
56 changes: 56 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions bmc/bmc.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ type BMC interface {
// GetAccountService retrieves the account service.
GetAccountService() (*schemas.AccountService, error)

// GenerateCSR generates a Certificate Signing Request (CSR) with the provided parameters.
// The CSR can be submitted to a Certificate Authority for signing.
GenerateCSR(ctx context.Context, params CSRParameters) ([]byte, error)

// ReplaceCertificate replaces the BMC's TLS certificate with the provided certificate and private key.
// The certificate and privateKey should be PEM-encoded strings.
ReplaceCertificate(ctx context.Context, certificate, privateKey string) error

// GetCertificateInfo retrieves information about the BMC's current TLS certificate.
GetCertificateInfo(ctx context.Context) (*CertificateInfo, error)

// CheckBMCPendingComponentUpgrade checks if there are pending/staged firmware upgrades
// for the given component type.
CheckBMCPendingComponentUpgrade(ctx context.Context, componentType ComponentType) (bool, error)
Expand Down Expand Up @@ -297,3 +308,39 @@ type Manager struct {
MACAddress string
OemLinks json.RawMessage
}

// CSRParameters contains the parameters for generating a Certificate Signing Request.
type CSRParameters struct {
// CommonName is the fully qualified domain name (FQDN) or IP address of the BMC.
CommonName string
// AlternativeNames is a list of Subject Alternative Names (SANs) for the certificate.
AlternativeNames []string
// Organization is the organization name for the certificate subject.
Organization string
// OrganizationalUnit is the organizational unit name for the certificate subject.
OrganizationalUnit string
// City is the city or locality name for the certificate subject.
City string
// State is the state or province name for the certificate subject.
State string
// Country is the two-letter country code for the certificate subject.
Country string
// KeyPairAlgorithm specifies the algorithm used for key pair generation (e.g., "RSA", "EC").
KeyPairAlgorithm string
// KeyBitLength specifies the bit length of the key (e.g., 2048, 4096 for RSA).
KeyBitLength int
}

// CertificateInfo contains information about a TLS certificate.
type CertificateInfo struct {
// Subject contains the certificate subject information (e.g., "CN=bmc.example.com,O=Example Org").
Subject string
// Issuer contains the certificate issuer information.
Issuer string
// ValidFrom is the certificate's validity start date.
ValidFrom string
// ValidUntil is the certificate's validity end date.
ValidUntil string
// SerialNumber is the certificate's serial number.
SerialNumber string
}
6 changes: 4 additions & 2 deletions bmc/mockup.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ type RedfishMockUps struct {
BMCUpgradeTaskIndex int
BMCUpgradeTaskStatus []schemas.Task

Accounts map[string]*schemas.ManagerAccount
SimulateUnvailableBMC bool
Accounts map[string]*schemas.ManagerAccount
SimulateUnvailableBMC bool
SimulateCSRGenerationFailure bool
}

func (r *RedfishMockUps) InitializeDefaults() {
Expand Down Expand Up @@ -145,6 +146,7 @@ func (r *RedfishMockUps) InitializeDefaults() {
},
}
r.SimulateUnvailableBMC = false
r.SimulateCSRGenerationFailure = false
}

func (r *RedfishMockUps) ResetBIOSSettings() {
Expand Down
Loading
Loading