certs.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. // Package providercerts manages TLS certificates for external secrets providers.
  13. package providercerts
  14. import (
  15. "context"
  16. "crypto/rand"
  17. "crypto/rsa"
  18. "crypto/x509"
  19. "crypto/x509/pkix"
  20. "encoding/pem"
  21. "fmt"
  22. "math/big"
  23. "time"
  24. corev1 "k8s.io/api/core/v1"
  25. apierrors "k8s.io/apimachinery/pkg/api/errors"
  26. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  27. "k8s.io/apimachinery/pkg/types"
  28. )
  29. const (
  30. caCertName = "ca.crt"
  31. caKeyName = "ca.key"
  32. certName = "tls.crt"
  33. keyName = "tls.key"
  34. clientCertName = "client.crt"
  35. clientKeyName = "client.key"
  36. // we're using a fixed secret name for the provider certificates
  37. // otherwise we would need to introduce a lot of complexity to the core controller
  38. // because we would have to maintain a mapping of provider names (aws) to provider kinds (parameterstore, generators etc.)
  39. providerSecretName = "external-secrets-provider-tls"
  40. // certValidityDuration is the validity period for generated certificates (10 years).
  41. certValidityDuration = 87600 * time.Hour
  42. )
  43. // ProviderCertConfig defines configuration for a single provider's certificates.
  44. type ProviderCertConfig struct {
  45. Namespace string // Namespace where provider is deployed
  46. ServiceNames []string // Service names for DNS SANs
  47. }
  48. // ProviderCertificates holds the generated certificates for a provider.
  49. type ProviderCertificates struct {
  50. ServerCert []byte
  51. ServerKey []byte
  52. ClientCert []byte
  53. ClientKey []byte
  54. }
  55. // KeyPairArtifacts holds a certificate and private key.
  56. type KeyPairArtifacts struct {
  57. Cert *x509.Certificate
  58. Key *rsa.PrivateKey
  59. CertPEM []byte
  60. KeyPEM []byte
  61. }
  62. // ReconcileProviderCert ensures provider certificates exist and are valid.
  63. func (r *ProviderCertReconciler) ReconcileProviderCert(ctx context.Context, config *ProviderCertConfig) error {
  64. if config == nil {
  65. return nil
  66. }
  67. log := r.Log.WithValues("secret", providerSecretName, "namespace", config.Namespace)
  68. // Get or create the secret
  69. secretName := types.NamespacedName{
  70. Name: providerSecretName,
  71. Namespace: config.Namespace,
  72. }
  73. var secret corev1.Secret
  74. err := r.Get(ctx, secretName, &secret)
  75. if err != nil {
  76. if !apierrors.IsNotFound(err) {
  77. return fmt.Errorf("failed to get provider secret: %w", err)
  78. }
  79. // Secret doesn't exist, create it
  80. log.Info("creating provider certificate secret")
  81. secret = corev1.Secret{
  82. ObjectMeta: metav1.ObjectMeta{
  83. Name: providerSecretName,
  84. Namespace: config.Namespace,
  85. Labels: map[string]string{
  86. "app.kubernetes.io/managed-by": "external-secrets",
  87. "app.kubernetes.io/component": "provider-certificates",
  88. },
  89. },
  90. Type: corev1.SecretTypeTLS,
  91. }
  92. }
  93. // Check if certificates need refresh
  94. needRefresh := r.needProviderCertRefresh(&secret, config)
  95. if needRefresh {
  96. log.Info("refreshing provider certificates")
  97. if err := r.refreshProviderCerts(&secret, config); err != nil {
  98. return fmt.Errorf("failed to refresh provider certificates: %w", err)
  99. }
  100. // Create or update the secret
  101. if secret.UID == "" {
  102. if err := r.Create(ctx, &secret); err != nil {
  103. return fmt.Errorf("failed to create provider secret: %w", err)
  104. }
  105. log.Info("created provider certificate secret")
  106. } else {
  107. if err := r.Update(ctx, &secret); err != nil {
  108. return fmt.Errorf("failed to update provider secret: %w", err)
  109. }
  110. log.Info("updated provider certificate secret")
  111. }
  112. }
  113. return nil
  114. }
  115. // needProviderCertRefresh checks if provider certificates need to be refreshed.
  116. func (r *ProviderCertReconciler) needProviderCertRefresh(secret *corev1.Secret, config *ProviderCertConfig) bool {
  117. // If secret has no data, we need to generate certificates
  118. if secret.Data == nil {
  119. return true
  120. }
  121. // Check if all required keys exist
  122. requiredKeys := []string{caCertName, caKeyName, certName, keyName, clientCertName, clientKeyName}
  123. for _, key := range requiredKeys {
  124. if _, ok := secret.Data[key]; !ok {
  125. return true
  126. }
  127. }
  128. // Validate CA certificate
  129. if !r.validCACert(secret.Data[caCertName], secret.Data[caKeyName]) {
  130. return true
  131. }
  132. // Validate server certificate
  133. dnsNames := r.getProviderDNSNames(config)
  134. if !r.validProviderCert(secret.Data[caCertName], secret.Data[certName], secret.Data[keyName], dnsNames) {
  135. return true
  136. }
  137. // Validate client certificate
  138. if !r.validProviderClientCert(secret.Data[caCertName], secret.Data[clientCertName], secret.Data[clientKeyName]) {
  139. return true
  140. }
  141. return false
  142. }
  143. // refreshProviderCerts generates new certificates for the provider.
  144. func (r *ProviderCertReconciler) refreshProviderCerts(secret *corev1.Secret, config *ProviderCertConfig) error {
  145. now := time.Now()
  146. begin := now.Add(-1 * time.Hour)
  147. end := now.Add(certValidityDuration)
  148. // Check if we need to generate a new CA or reuse existing
  149. var caArtifacts *KeyPairArtifacts
  150. var err error
  151. if secret.Data != nil && r.validCACert(secret.Data[caCertName], secret.Data[caKeyName]) {
  152. // Reuse existing CA
  153. caArtifacts, err = buildArtifactsFromSecret(secret)
  154. if err != nil {
  155. return fmt.Errorf("failed to load existing CA: %w", err)
  156. }
  157. } else {
  158. // Generate new CA
  159. caArtifacts, err = r.createCACert(begin, end)
  160. if err != nil {
  161. return fmt.Errorf("failed to create CA certificate: %w", err)
  162. }
  163. }
  164. // Generate server certificate
  165. serverCert, serverKey, err := r.createProviderServerCert(caArtifacts, config, begin, end)
  166. if err != nil {
  167. return fmt.Errorf("failed to create server certificate: %w", err)
  168. }
  169. // Generate client certificate
  170. clientCert, clientKey, err := r.createProviderClientCert(caArtifacts, begin, end)
  171. if err != nil {
  172. return fmt.Errorf("failed to create client certificate: %w", err)
  173. }
  174. // Populate secret
  175. if secret.Data == nil {
  176. secret.Data = make(map[string][]byte)
  177. }
  178. secret.Data[caCertName] = caArtifacts.CertPEM
  179. secret.Data[caKeyName] = caArtifacts.KeyPEM
  180. secret.Data[certName] = serverCert
  181. secret.Data[keyName] = serverKey
  182. secret.Data[clientCertName] = clientCert
  183. secret.Data[clientKeyName] = clientKey
  184. return nil
  185. }
  186. // createCACert creates a new CA certificate.
  187. func (r *ProviderCertReconciler) createCACert(begin, end time.Time) (*KeyPairArtifacts, error) {
  188. template := &x509.Certificate{
  189. SerialNumber: big.NewInt(0),
  190. Subject: pkix.Name{
  191. CommonName: r.CAName,
  192. Organization: []string{r.CAOrganization},
  193. },
  194. DNSNames: []string{r.CAName},
  195. NotBefore: begin,
  196. NotAfter: end,
  197. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
  198. BasicConstraintsValid: true,
  199. IsCA: true,
  200. }
  201. key, err := rsa.GenerateKey(rand.Reader, 2048)
  202. if err != nil {
  203. return nil, fmt.Errorf("failed to generate private key: %w", err)
  204. }
  205. certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
  206. if err != nil {
  207. return nil, fmt.Errorf("failed to create certificate: %w", err)
  208. }
  209. cert, err := x509.ParseCertificate(certDER)
  210. if err != nil {
  211. return nil, fmt.Errorf("failed to parse certificate: %w", err)
  212. }
  213. certPEM := pem.EncodeToMemory(&pem.Block{
  214. Type: "CERTIFICATE",
  215. Bytes: certDER,
  216. })
  217. keyPEM := pem.EncodeToMemory(&pem.Block{
  218. Type: "RSA PRIVATE KEY",
  219. Bytes: x509.MarshalPKCS1PrivateKey(key),
  220. })
  221. return &KeyPairArtifacts{
  222. Cert: cert,
  223. Key: key,
  224. CertPEM: certPEM,
  225. KeyPEM: keyPEM,
  226. }, nil
  227. }
  228. // createProviderServerCert generates a server certificate for the provider.
  229. func (r *ProviderCertReconciler) createProviderServerCert(
  230. caArtifacts *KeyPairArtifacts,
  231. config *ProviderCertConfig,
  232. begin, end time.Time,
  233. ) ([]byte, []byte, error) {
  234. dnsNames := r.getProviderDNSNames(config)
  235. // Create certificate template
  236. template := &x509.Certificate{
  237. SerialNumber: big.NewInt(time.Now().UnixNano()),
  238. Subject: pkix.Name{
  239. CommonName: "external-secrets-provider",
  240. Organization: []string{r.CAOrganization},
  241. },
  242. DNSNames: dnsNames,
  243. NotBefore: begin,
  244. NotAfter: end,
  245. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  246. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  247. }
  248. // Generate private key
  249. key, err := rsa.GenerateKey(rand.Reader, 2048)
  250. if err != nil {
  251. return nil, nil, fmt.Errorf("failed to generate private key: %w", err)
  252. }
  253. // Create certificate
  254. certDER, err := x509.CreateCertificate(rand.Reader, template, caArtifacts.Cert, &key.PublicKey, caArtifacts.Key)
  255. if err != nil {
  256. return nil, nil, fmt.Errorf("failed to create certificate: %w", err)
  257. }
  258. // Encode certificate
  259. certPEM := pem.EncodeToMemory(&pem.Block{
  260. Type: "CERTIFICATE",
  261. Bytes: certDER,
  262. })
  263. // Encode private key
  264. keyPEM := pem.EncodeToMemory(&pem.Block{
  265. Type: "RSA PRIVATE KEY",
  266. Bytes: x509.MarshalPKCS1PrivateKey(key),
  267. })
  268. return certPEM, keyPEM, nil
  269. }
  270. // createProviderClientCert generates a client certificate for the ESO controller.
  271. func (r *ProviderCertReconciler) createProviderClientCert(
  272. caArtifacts *KeyPairArtifacts,
  273. begin, end time.Time,
  274. ) ([]byte, []byte, error) {
  275. // Create certificate template
  276. template := &x509.Certificate{
  277. SerialNumber: big.NewInt(time.Now().UnixNano()),
  278. Subject: pkix.Name{
  279. CommonName: "external-secrets-controller",
  280. Organization: []string{r.CAOrganization},
  281. },
  282. NotBefore: begin,
  283. NotAfter: end,
  284. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  285. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
  286. }
  287. // Generate private key
  288. key, err := rsa.GenerateKey(rand.Reader, 2048)
  289. if err != nil {
  290. return nil, nil, fmt.Errorf("failed to generate private key: %w", err)
  291. }
  292. // Create certificate
  293. certDER, err := x509.CreateCertificate(rand.Reader, template, caArtifacts.Cert, &key.PublicKey, caArtifacts.Key)
  294. if err != nil {
  295. return nil, nil, fmt.Errorf("failed to create certificate: %w", err)
  296. }
  297. // Encode certificate
  298. certPEM := pem.EncodeToMemory(&pem.Block{
  299. Type: "CERTIFICATE",
  300. Bytes: certDER,
  301. })
  302. // Encode private key
  303. keyPEM := pem.EncodeToMemory(&pem.Block{
  304. Type: "RSA PRIVATE KEY",
  305. Bytes: x509.MarshalPKCS1PrivateKey(key),
  306. })
  307. return certPEM, keyPEM, nil
  308. }
  309. // getProviderDNSNames returns the DNS names for the provider service.
  310. func (r *ProviderCertReconciler) getProviderDNSNames(config *ProviderCertConfig) []string {
  311. dnsNames := make([]string, 0, len(config.ServiceNames)*4)
  312. for _, serviceName := range config.ServiceNames {
  313. dnsNames = append(dnsNames,
  314. serviceName,
  315. fmt.Sprintf("%s.%s", serviceName, config.Namespace),
  316. fmt.Sprintf("%s.%s.svc", serviceName, config.Namespace),
  317. fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, config.Namespace),
  318. )
  319. }
  320. return dnsNames
  321. }
  322. // validCACert validates a CA certificate.
  323. func (r *ProviderCertReconciler) validCACert(caCert, caKey []byte) bool {
  324. if len(caCert) == 0 || len(caKey) == 0 {
  325. return false
  326. }
  327. // Parse CA certificate
  328. caDer, _ := pem.Decode(caCert)
  329. if caDer == nil {
  330. return false
  331. }
  332. caCertParsed, err := x509.ParseCertificate(caDer.Bytes)
  333. if err != nil {
  334. return false
  335. }
  336. // Check if CA is still valid with lookahead
  337. if time.Now().After(lookaheadTime()) && lookaheadTime().After(caCertParsed.NotAfter) {
  338. return false
  339. }
  340. return true
  341. }
  342. // validProviderCert validates a provider server certificate.
  343. func (r *ProviderCertReconciler) validProviderCert(caCert, cert, key []byte, dnsNames []string) bool {
  344. if len(caCert) == 0 || len(cert) == 0 || len(key) == 0 {
  345. return false
  346. }
  347. // Parse CA certificate
  348. pool := x509.NewCertPool()
  349. caDer, _ := pem.Decode(caCert)
  350. if caDer == nil {
  351. return false
  352. }
  353. caCertParsed, err := x509.ParseCertificate(caDer.Bytes)
  354. if err != nil {
  355. return false
  356. }
  357. pool.AddCert(caCertParsed)
  358. // Parse server certificate
  359. certDer, _ := pem.Decode(cert)
  360. if certDer == nil {
  361. return false
  362. }
  363. certParsed, err := x509.ParseCertificate(certDer.Bytes)
  364. if err != nil {
  365. return false
  366. }
  367. // Verify certificate is signed by CA
  368. opts := x509.VerifyOptions{
  369. Roots: pool,
  370. CurrentTime: lookaheadTime(),
  371. KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  372. }
  373. if _, err := certParsed.Verify(opts); err != nil {
  374. return false
  375. }
  376. // Check DNS names are present
  377. for _, dnsName := range dnsNames {
  378. found := false
  379. for _, certDNS := range certParsed.DNSNames {
  380. if certDNS == dnsName {
  381. found = true
  382. break
  383. }
  384. }
  385. if !found {
  386. return false
  387. }
  388. }
  389. return true
  390. }
  391. // validProviderClientCert validates a provider client certificate.
  392. func (r *ProviderCertReconciler) validProviderClientCert(caCert, cert, key []byte) bool {
  393. if len(caCert) == 0 || len(cert) == 0 || len(key) == 0 {
  394. return false
  395. }
  396. // Parse CA certificate
  397. pool := x509.NewCertPool()
  398. caDer, _ := pem.Decode(caCert)
  399. if caDer == nil {
  400. return false
  401. }
  402. caCertParsed, err := x509.ParseCertificate(caDer.Bytes)
  403. if err != nil {
  404. return false
  405. }
  406. pool.AddCert(caCertParsed)
  407. // Parse client certificate
  408. certDer, _ := pem.Decode(cert)
  409. if certDer == nil {
  410. return false
  411. }
  412. certParsed, err := x509.ParseCertificate(certDer.Bytes)
  413. if err != nil {
  414. return false
  415. }
  416. // Verify certificate is signed by CA
  417. opts := x509.VerifyOptions{
  418. Roots: pool,
  419. CurrentTime: lookaheadTime(),
  420. KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
  421. }
  422. if _, err := certParsed.Verify(opts); err != nil {
  423. return false
  424. }
  425. return true
  426. }
  427. // buildArtifactsFromSecret builds KeyPairArtifacts from a secret.
  428. func buildArtifactsFromSecret(secret *corev1.Secret) (*KeyPairArtifacts, error) {
  429. caCertPEM := secret.Data[caCertName]
  430. caKeyPEM := secret.Data[caKeyName]
  431. caDer, _ := pem.Decode(caCertPEM)
  432. if caDer == nil {
  433. return nil, fmt.Errorf("failed to decode CA certificate")
  434. }
  435. caCert, err := x509.ParseCertificate(caDer.Bytes)
  436. if err != nil {
  437. return nil, fmt.Errorf("failed to parse CA certificate: %w", err)
  438. }
  439. keyDer, _ := pem.Decode(caKeyPEM)
  440. if keyDer == nil {
  441. return nil, fmt.Errorf("failed to decode CA key")
  442. }
  443. caKey, err := x509.ParsePKCS1PrivateKey(keyDer.Bytes)
  444. if err != nil {
  445. return nil, fmt.Errorf("failed to parse CA key: %w", err)
  446. }
  447. return &KeyPairArtifacts{
  448. Cert: caCert,
  449. Key: caKey,
  450. CertPEM: caCertPEM,
  451. KeyPEM: caKeyPEM,
  452. }, nil
  453. }
  454. // lookaheadTime returns the current time plus a lookahead duration
  455. // to ensure certificates are refreshed before expiration.
  456. func lookaheadTime() time.Time {
  457. return time.Now().Add(365 * 24 * time.Hour) // 1 year lookahead
  458. }