A Kubernetes operator that bridges Hardware Security Module (HSM) data storage with Kubernetes Secrets, providing true secret portability th
1/*
2Copyright 2025.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package api
18
19import (
20 "time"
21
22 "github.com/evanjarrett/hsm-secrets-operator/internal/hsm"
23)
24
25// SecretFormat defines the format of the secret data
26type SecretFormat string
27
28const (
29 // SecretFormatJSON stores data as JSON key-value pairs
30 SecretFormatJSON SecretFormat = "json"
31 // SecretFormatBinary stores raw binary data
32 SecretFormatBinary SecretFormat = "binary"
33 // SecretFormatText stores plain text data
34 SecretFormatText SecretFormat = "text"
35)
36
37// CreateSecretRequest represents a request to create a new secret
38type CreateSecretRequest struct {
39 // Label is the human-readable identifier for the secret
40 Label string `json:"label" validate:"required,min=1,max=255"`
41
42 // ID is the unique numeric identifier for the secret on the HSM
43 ID uint32 `json:"id" validate:"required,min=1"`
44
45 // Format specifies how the data should be stored
46 Format SecretFormat `json:"format" validate:"required,oneof=json binary text"`
47
48 // Data contains the actual secret data
49 Data map[string]any `json:"data" validate:"required"`
50
51 // Description is an optional description of the secret
52 Description string `json:"description,omitempty" validate:"max=1000"`
53
54 // Tags are optional metadata tags
55 Tags map[string]string `json:"tags,omitempty"`
56}
57
58// UpdateSecretRequest represents a request to update an existing secret
59type UpdateSecretRequest struct {
60 // Data contains the updated secret data
61 Data map[string]any `json:"data" validate:"required"`
62
63 // Description is an optional updated description
64 Description string `json:"description,omitempty" validate:"max=1000"`
65
66 // Tags are optional updated metadata tags
67 Tags map[string]string `json:"tags,omitempty"`
68}
69
70// ImportSecretRequest represents a request to import a secret from external source
71type ImportSecretRequest struct {
72 // Source specifies where to import from (kubernetes, vault, etc.)
73 Source string `json:"source" validate:"required,oneof=kubernetes vault file"`
74
75 // SecretName is the name of the source secret
76 SecretName string `json:"secret_name" validate:"required"`
77
78 // SecretNamespace is the namespace for Kubernetes secrets
79 SecretNamespace string `json:"secret_namespace,omitempty"`
80
81 // TargetLabel is the label for the imported secret on HSM
82 TargetLabel string `json:"target_label" validate:"required,min=1,max=255"`
83
84 // TargetID is the ID for the imported secret on HSM
85 TargetID uint32 `json:"target_id" validate:"required,min=1"`
86
87 // Format specifies how the imported data should be stored
88 Format SecretFormat `json:"format" validate:"required,oneof=json binary text"`
89
90 // KeyMapping maps source keys to target keys (optional)
91 KeyMapping map[string]string `json:"key_mapping,omitempty"`
92}
93
94// SecretInfo represents information about a secret
95type SecretInfo struct {
96 // Label is the human-readable identifier
97 Label string `json:"label"`
98
99 // ID is the unique numeric identifier on the HSM
100 ID uint32 `json:"id"`
101
102 // Format specifies the data format
103 Format SecretFormat `json:"format"`
104
105 // Description is the secret description
106 Description string `json:"description,omitempty"`
107
108 // Tags are metadata tags
109 Tags map[string]string `json:"tags,omitempty"`
110
111 // CreatedAt is when the secret was created
112 CreatedAt time.Time `json:"created_at"`
113
114 // UpdatedAt is when the secret was last updated
115 UpdatedAt time.Time `json:"updated_at"`
116
117 // Size is the size of the secret data in bytes
118 Size int64 `json:"size"`
119
120 // Checksum is the SHA256 checksum of the data
121 Checksum string `json:"checksum"`
122
123 // IsReplicated indicates if the secret is replicated across nodes
124 IsReplicated bool `json:"is_replicated"`
125}
126
127// SecretData represents the actual secret data
128type SecretData struct {
129 // Data contains the secret key-value pairs
130 Data map[string]any `json:"data"`
131
132 // Metadata contains additional information about the secret
133 Metadata SecretInfo `json:"metadata"`
134}
135
136// SecretList represents a list of secrets
137type SecretList struct {
138 // Secrets is the list of secret information
139 Secrets []SecretInfo `json:"secrets"`
140
141 // Total is the total number of secrets
142 Total int `json:"total"`
143
144 // Page is the current page number (for pagination)
145 Page int `json:"page,omitempty"`
146
147 // PageSize is the number of items per page
148 PageSize int `json:"page_size,omitempty"`
149}
150
151// APIResponse represents a standard API response
152type APIResponse struct {
153 // Success indicates if the operation was successful
154 Success bool `json:"success"`
155
156 // Message provides additional information about the result
157 Message string `json:"message,omitempty"`
158
159 // Data contains the response data
160 Data any `json:"data,omitempty"`
161
162 // Error contains error details if the operation failed
163 Error *APIError `json:"error,omitempty"`
164}
165
166// APIError represents an API error
167type APIError struct {
168 // Code is the error code
169 Code string `json:"code"`
170
171 // Message is the human-readable error message
172 Message string `json:"message"`
173
174 // Details contains additional error details
175 Details map[string]any `json:"details,omitempty"`
176}
177
178// HealthStatus represents the health status of the API server
179type HealthStatus struct {
180 // Status is the overall health status
181 Status string `json:"status"`
182
183 // HSMConnected indicates if HSM is connected
184 HSMConnected bool `json:"hsm_connected"`
185
186 // ReplicationEnabled indicates if replication is enabled
187 ReplicationEnabled bool `json:"replication_enabled"`
188
189 // ActiveNodes is the number of active HSM nodes
190 ActiveNodes int `json:"active_nodes"`
191
192 // Timestamp is when the health check was performed
193 Timestamp time.Time `json:"timestamp"`
194}
195
196// ListSecretsResponse represents the response for listing secrets
197type ListSecretsResponse struct {
198 Secrets []string `json:"secrets"`
199 Count int `json:"count"`
200 Prefix string `json:"prefix,omitempty"`
201}
202
203// ReadSecretResponse represents the response for reading a secret
204type ReadSecretResponse struct {
205 Path string `json:"path"`
206 Data map[string][]byte `json:"data"`
207 Checksum string `json:"checksum,omitempty"`
208 DeviceCount int `json:"deviceCount,omitempty"`
209}
210
211// WriteSecretResponse represents the response for writing a secret
212type WriteSecretResponse struct {
213 Path string `json:"path"`
214 Keys int `json:"keys"`
215}
216
217// DeleteSecretResponse represents the response for deleting a secret
218type DeleteSecretResponse struct {
219 Path string `json:"path"`
220 Devices int `json:"devices"`
221 DeviceResults map[string]any `json:"deviceResults"`
222 Warnings []string `json:"warnings,omitempty"`
223}
224
225// ReadMetadataResponse represents the response for reading metadata
226type ReadMetadataResponse struct {
227 Path string `json:"path"`
228 Metadata *hsm.SecretMetadata `json:"metadata"`
229}
230
231// GetChecksumResponse represents the response for getting a checksum
232type GetChecksumResponse struct {
233 Path string `json:"path"`
234 Checksum string `json:"checksum"`
235}
236
237type IsConnectedResponse struct {
238 Devices map[string]bool `json:"devices"`
239 TotalDevices int `json:"totalDevices"`
240}
241
242// GetInfoResponse represents the response for getting HSM info
243type GetInfoResponse struct {
244 DeviceInfos map[string]*hsm.HSMInfo `json:"deviceInfos"` // deviceName -> HSMInfo
245}
246
247// ChangePINRequest represents a request to change HSM PIN
248type ChangePINRequest struct {
249 OldPIN string `json:"old_pin" validate:"required"`
250 NewPIN string `json:"new_pin" validate:"required"`
251}