controller_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package provider
  14. import (
  15. "context"
  16. "crypto/rand"
  17. "crypto/rsa"
  18. "crypto/tls"
  19. "crypto/x509"
  20. "crypto/x509/pkix"
  21. "encoding/pem"
  22. "math/big"
  23. "net"
  24. "testing"
  25. "time"
  26. "github.com/go-logr/logr"
  27. "github.com/prometheus/client_golang/prometheus"
  28. "google.golang.org/grpc"
  29. "google.golang.org/grpc/codes"
  30. "google.golang.org/grpc/credentials"
  31. "google.golang.org/grpc/status"
  32. corev1 "k8s.io/api/core/v1"
  33. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  34. "k8s.io/apimachinery/pkg/runtime"
  35. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
  36. clientgoscheme "k8s.io/client-go/kubernetes/scheme"
  37. ctrl "sigs.k8s.io/controller-runtime"
  38. "sigs.k8s.io/controller-runtime/pkg/client"
  39. fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
  40. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  41. k8sv2alpha1 "github.com/external-secrets/external-secrets/apis/provider/kubernetes/v2alpha1"
  42. ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
  43. pb "github.com/external-secrets/external-secrets/proto/provider"
  44. )
  45. type recordingProviderGRPCServer struct {
  46. pb.UnimplementedSecretStoreProviderServer
  47. validateRequest *pb.ValidateRequest
  48. validateResponse *pb.ValidateResponse
  49. capabilitiesRequest *pb.CapabilitiesRequest
  50. capabilitiesResp *pb.CapabilitiesResponse
  51. capabilitiesErr error
  52. }
  53. func (s *recordingProviderGRPCServer) Validate(_ context.Context, req *pb.ValidateRequest) (*pb.ValidateResponse, error) {
  54. s.validateRequest = req
  55. if s.validateResponse != nil {
  56. return s.validateResponse, nil
  57. }
  58. return &pb.ValidateResponse{Valid: true}, nil
  59. }
  60. func (s *recordingProviderGRPCServer) Capabilities(_ context.Context, req *pb.CapabilitiesRequest) (*pb.CapabilitiesResponse, error) {
  61. s.capabilitiesRequest = req
  62. if s.capabilitiesErr != nil {
  63. return nil, s.capabilitiesErr
  64. }
  65. if s.capabilitiesResp != nil {
  66. return s.capabilitiesResp, nil
  67. }
  68. return &pb.CapabilitiesResponse{Capabilities: pb.SecretStoreCapabilities_READ_WRITE}, nil
  69. }
  70. func TestValidateStoreAndGetCapabilitiesSendsProviderReferenceAndNamespace(t *testing.T) {
  71. scheme := runtime.NewScheme()
  72. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  73. utilruntime.Must(esv1.AddToScheme(scheme))
  74. server, address, tlsSecret := newProviderGRPCServer(t)
  75. store := &esv1.Provider{
  76. ObjectMeta: metav1.ObjectMeta{
  77. Name: "provider",
  78. Namespace: "tenant-a",
  79. },
  80. Spec: esv1.ProviderSpec{
  81. Config: esv1.ProviderConfig{
  82. Address: address,
  83. ProviderRef: esv1.ProviderReference{
  84. APIVersion: "provider.external-secrets.io/v2alpha1",
  85. Kind: "Kubernetes",
  86. Name: "backend",
  87. Namespace: "config-ns",
  88. },
  89. },
  90. },
  91. }
  92. kubeClient := fakeclient.NewClientBuilder().
  93. WithScheme(scheme).
  94. WithObjects(store, &corev1.Secret{
  95. ObjectMeta: metav1.ObjectMeta{
  96. Name: "external-secrets-provider-tls",
  97. Namespace: "tenant-a",
  98. },
  99. Data: tlsSecret,
  100. }).
  101. Build()
  102. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  103. caps, err := r.validateStoreAndGetCapabilities(context.Background(), store)
  104. if err != nil {
  105. t.Fatalf("validateStoreAndGetCapabilities() error = %v", err)
  106. }
  107. if caps != esv1.ProviderReadWrite {
  108. t.Fatalf("expected ProviderReadWrite, got %q", caps)
  109. }
  110. assertProviderReference(t, server.validateRequest.ProviderRef, store.Spec.Config.ProviderRef, esv1.ProviderKindStr)
  111. if server.validateRequest.SourceNamespace != "tenant-a" {
  112. t.Fatalf("unexpected validate source namespace: %q", server.validateRequest.SourceNamespace)
  113. }
  114. assertProviderReference(t, server.capabilitiesRequest.ProviderRef, store.Spec.Config.ProviderRef, esv1.ProviderKindStr)
  115. if server.capabilitiesRequest.SourceNamespace != "tenant-a" {
  116. t.Fatalf("unexpected capabilities source namespace: %q", server.capabilitiesRequest.SourceNamespace)
  117. }
  118. }
  119. func TestValidateStoreAndGetCapabilitiesFallsBackToReadOnlyOnCapabilitiesError(t *testing.T) {
  120. scheme := runtime.NewScheme()
  121. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  122. utilruntime.Must(esv1.AddToScheme(scheme))
  123. server, address, tlsSecret := newProviderGRPCServer(t)
  124. server.capabilitiesErr = status.Error(codes.Unavailable, "capabilities unavailable")
  125. store := &esv1.Provider{
  126. ObjectMeta: metav1.ObjectMeta{
  127. Name: "provider",
  128. Namespace: "tenant-a",
  129. },
  130. Spec: esv1.ProviderSpec{
  131. Config: esv1.ProviderConfig{
  132. Address: address,
  133. ProviderRef: esv1.ProviderReference{
  134. APIVersion: "provider.external-secrets.io/v2alpha1",
  135. Kind: "Kubernetes",
  136. Name: "backend",
  137. },
  138. },
  139. },
  140. }
  141. kubeClient := fakeclient.NewClientBuilder().
  142. WithScheme(scheme).
  143. WithObjects(store, &corev1.Secret{
  144. ObjectMeta: metav1.ObjectMeta{
  145. Name: "external-secrets-provider-tls",
  146. Namespace: "tenant-a",
  147. },
  148. Data: tlsSecret,
  149. }).
  150. Build()
  151. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  152. caps, err := r.validateStoreAndGetCapabilities(context.Background(), store)
  153. if err != nil {
  154. t.Fatalf("expected fallback to read-only, got error %v", err)
  155. }
  156. if caps != esv1.ProviderReadOnly {
  157. t.Fatalf("expected ProviderReadOnly, got %q", caps)
  158. }
  159. }
  160. func TestValidateStoreAndGetCapabilitiesReturnsValidationError(t *testing.T) {
  161. scheme := runtime.NewScheme()
  162. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  163. utilruntime.Must(esv1.AddToScheme(scheme))
  164. server, address, tlsSecret := newProviderGRPCServer(t)
  165. server.validateResponse = &pb.ValidateResponse{
  166. Valid: false,
  167. Error: "invalid credentials",
  168. }
  169. store := &esv1.Provider{
  170. ObjectMeta: metav1.ObjectMeta{
  171. Name: "provider",
  172. Namespace: "tenant-a",
  173. },
  174. Spec: esv1.ProviderSpec{
  175. Config: esv1.ProviderConfig{
  176. Address: address,
  177. ProviderRef: esv1.ProviderReference{
  178. APIVersion: "provider.external-secrets.io/v2alpha1",
  179. Kind: "Kubernetes",
  180. Name: "backend",
  181. },
  182. },
  183. },
  184. }
  185. kubeClient := fakeclient.NewClientBuilder().
  186. WithScheme(scheme).
  187. WithObjects(store, &corev1.Secret{
  188. ObjectMeta: metav1.ObjectMeta{
  189. Name: "external-secrets-provider-tls",
  190. Namespace: "tenant-a",
  191. },
  192. Data: tlsSecret,
  193. }).
  194. Build()
  195. r := &Reconciler{Client: kubeClient, Log: logr.Discard()}
  196. _, err := r.validateStoreAndGetCapabilities(context.Background(), store)
  197. if err == nil || err.Error() != "provider validation failed: provider validation failed: invalid credentials" {
  198. t.Fatalf("unexpected error: %v", err)
  199. }
  200. }
  201. func TestReconcileValidationFailureClearsStaleCapabilitiesAndUpdatesCondition(t *testing.T) {
  202. ctrlmetrics.SetUpLabelNames(false)
  203. previousMetrics := gaugeVecMetrics
  204. gaugeVecMetrics = map[string]*prometheus.GaugeVec{
  205. ProviderReconcileDurationKey: prometheus.NewGaugeVec(prometheus.GaugeOpts{
  206. Subsystem: ProviderSubsystem,
  207. Name: ProviderReconcileDurationKey,
  208. }, ctrlmetrics.NonConditionMetricLabelNames),
  209. StatusConditionKey: prometheus.NewGaugeVec(prometheus.GaugeOpts{
  210. Subsystem: ProviderSubsystem,
  211. Name: StatusConditionKey,
  212. }, ctrlmetrics.ConditionMetricLabelNames),
  213. }
  214. t.Cleanup(func() {
  215. gaugeVecMetrics = previousMetrics
  216. })
  217. scheme := runtime.NewScheme()
  218. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  219. utilruntime.Must(esv1.AddToScheme(scheme))
  220. server, address, tlsSecret := newProviderGRPCServer(t)
  221. server.validateResponse = &pb.ValidateResponse{
  222. Valid: false,
  223. Error: "invalid credentials",
  224. }
  225. store := &esv1.Provider{
  226. ObjectMeta: metav1.ObjectMeta{
  227. Name: "provider",
  228. Namespace: "tenant-a",
  229. },
  230. Spec: esv1.ProviderSpec{
  231. Config: esv1.ProviderConfig{
  232. Address: address,
  233. ProviderRef: esv1.ProviderReference{
  234. APIVersion: "provider.external-secrets.io/v2alpha1",
  235. Kind: "Kubernetes",
  236. Name: "backend",
  237. },
  238. },
  239. },
  240. Status: esv1.ProviderStatus{
  241. Capabilities: esv1.ProviderReadWrite,
  242. },
  243. }
  244. kubeClient := fakeclient.NewClientBuilder().
  245. WithScheme(scheme).
  246. WithObjects(store, &corev1.Secret{
  247. ObjectMeta: metav1.ObjectMeta{
  248. Name: "external-secrets-provider-tls",
  249. Namespace: "tenant-a",
  250. },
  251. Data: tlsSecret,
  252. }).
  253. WithStatusSubresource(store).
  254. Build()
  255. r := &Reconciler{
  256. Client: kubeClient,
  257. Log: logr.Discard(),
  258. RequeueInterval: 37 * time.Second,
  259. }
  260. result, err := r.Reconcile(context.Background(), ctrl.Request{
  261. NamespacedName: client.ObjectKey{Name: "provider", Namespace: "tenant-a"},
  262. })
  263. if err != nil {
  264. t.Fatalf("Reconcile() error = %v", err)
  265. }
  266. if result.RequeueAfter != 37*time.Second {
  267. t.Fatalf("expected requeue interval, got %#v", result)
  268. }
  269. var updated esv1.Provider
  270. if err := kubeClient.Get(context.Background(), client.ObjectKey{Name: "provider", Namespace: "tenant-a"}, &updated); err != nil {
  271. t.Fatalf("Get() error = %v", err)
  272. }
  273. if updated.Status.Capabilities != "" {
  274. t.Fatalf("expected capabilities to be cleared, got %q", updated.Status.Capabilities)
  275. }
  276. if len(updated.Status.Conditions) != 1 {
  277. t.Fatalf("expected a single condition, got %#v", updated.Status.Conditions)
  278. }
  279. condition := updated.Status.Conditions[0]
  280. if condition.Type != esv1.ProviderReady || condition.Status != metav1.ConditionFalse {
  281. t.Fatalf("unexpected condition: %#v", condition)
  282. }
  283. if condition.Reason != "ValidationFailed" {
  284. t.Fatalf("unexpected condition reason: %q", condition.Reason)
  285. }
  286. if condition.Message != "provider validation failed: provider validation failed: invalid credentials" {
  287. t.Fatalf("unexpected condition message: %q", condition.Message)
  288. }
  289. }
  290. func TestSetNotReadyConditionUpdatesReasonAndMessageWithoutChangingTransitionTime(t *testing.T) {
  291. ctrlmetrics.SetUpLabelNames(false)
  292. previousMetrics := gaugeVecMetrics
  293. gaugeVecMetrics = map[string]*prometheus.GaugeVec{
  294. StatusConditionKey: prometheus.NewGaugeVec(prometheus.GaugeOpts{
  295. Subsystem: ProviderSubsystem,
  296. Name: StatusConditionKey,
  297. }, ctrlmetrics.ConditionMetricLabelNames),
  298. }
  299. t.Cleanup(func() {
  300. gaugeVecMetrics = previousMetrics
  301. })
  302. previousTransition := metav1.NewTime(time.Unix(1700000000, 0))
  303. store := &esv1.Provider{
  304. ObjectMeta: metav1.ObjectMeta{
  305. Name: "provider",
  306. Namespace: "tenant-a",
  307. },
  308. Status: esv1.ProviderStatus{
  309. Conditions: []esv1.ProviderCondition{{
  310. Type: esv1.ProviderReady,
  311. Status: metav1.ConditionFalse,
  312. LastTransitionTime: previousTransition,
  313. Reason: "OldReason",
  314. Message: "old message",
  315. }},
  316. },
  317. }
  318. r := &Reconciler{Log: logr.Discard()}
  319. r.setNotReadyCondition(store, "ValidationFailed", "new message")
  320. if len(store.Status.Conditions) != 1 {
  321. t.Fatalf("expected a single condition, got %#v", store.Status.Conditions)
  322. }
  323. condition := store.Status.Conditions[0]
  324. if condition.Status != metav1.ConditionFalse {
  325. t.Fatalf("expected false status, got %q", condition.Status)
  326. }
  327. if condition.Reason != "ValidationFailed" {
  328. t.Fatalf("expected updated reason, got %q", condition.Reason)
  329. }
  330. if condition.Message != "new message" {
  331. t.Fatalf("expected updated message, got %q", condition.Message)
  332. }
  333. if !condition.LastTransitionTime.Equal(&previousTransition) {
  334. t.Fatalf("expected transition time to remain %v, got %v", previousTransition, condition.LastTransitionTime)
  335. }
  336. }
  337. func TestFindProvidersForKubernetesProviderEnqueuesMatchingProviders(t *testing.T) {
  338. scheme := runtime.NewScheme()
  339. utilruntime.Must(clientgoscheme.AddToScheme(scheme))
  340. utilruntime.Must(esv1.AddToScheme(scheme))
  341. kubeClient := fakeclient.NewClientBuilder().
  342. WithScheme(scheme).
  343. WithObjects(
  344. &esv1.Provider{
  345. ObjectMeta: metav1.ObjectMeta{
  346. Name: "match",
  347. Namespace: "tenant-a",
  348. },
  349. Spec: esv1.ProviderSpec{
  350. Config: esv1.ProviderConfig{
  351. ProviderRef: esv1.ProviderReference{
  352. APIVersion: k8sv2alpha1.GroupVersion.String(),
  353. Kind: k8sv2alpha1.Kind,
  354. Name: "backend",
  355. Namespace: "config-ns",
  356. },
  357. },
  358. },
  359. },
  360. &esv1.Provider{
  361. ObjectMeta: metav1.ObjectMeta{
  362. Name: "wrong-name",
  363. Namespace: "tenant-a",
  364. },
  365. Spec: esv1.ProviderSpec{
  366. Config: esv1.ProviderConfig{
  367. ProviderRef: esv1.ProviderReference{
  368. APIVersion: k8sv2alpha1.GroupVersion.String(),
  369. Kind: k8sv2alpha1.Kind,
  370. Name: "other",
  371. Namespace: "config-ns",
  372. },
  373. },
  374. },
  375. },
  376. &esv1.Provider{
  377. ObjectMeta: metav1.ObjectMeta{
  378. Name: "wrong-kind",
  379. Namespace: "tenant-a",
  380. },
  381. Spec: esv1.ProviderSpec{
  382. Config: esv1.ProviderConfig{
  383. ProviderRef: esv1.ProviderReference{
  384. APIVersion: k8sv2alpha1.GroupVersion.String(),
  385. Kind: "AWS",
  386. Name: "backend",
  387. Namespace: "config-ns",
  388. },
  389. },
  390. },
  391. },
  392. ).
  393. Build()
  394. requests := findProvidersForKubernetesProvider(context.Background(), kubeClient, &k8sv2alpha1.Kubernetes{
  395. ObjectMeta: metav1.ObjectMeta{
  396. Name: "backend",
  397. Namespace: "config-ns",
  398. },
  399. })
  400. if len(requests) != 1 {
  401. t.Fatalf("expected one reconcile request, got %#v", requests)
  402. }
  403. if requests[0].NamespacedName != (client.ObjectKey{Name: "match", Namespace: "tenant-a"}) {
  404. t.Fatalf("unexpected reconcile request: %#v", requests[0])
  405. }
  406. }
  407. func newProviderGRPCServer(t *testing.T) (*recordingProviderGRPCServer, string, map[string][]byte) {
  408. t.Helper()
  409. serverCert, serverKey, clientCert, clientKey, caCert := newProviderTLSArtifacts(t, "127.0.0.1")
  410. caPool := x509.NewCertPool()
  411. if !caPool.AppendCertsFromPEM(caCert) {
  412. t.Fatal("failed to append CA cert")
  413. }
  414. tlsCert, err := tls.X509KeyPair(serverCert, serverKey)
  415. if err != nil {
  416. t.Fatalf("X509KeyPair() error = %v", err)
  417. }
  418. lis, err := net.Listen("tcp", "127.0.0.1:0")
  419. if err != nil {
  420. t.Fatalf("Listen() error = %v", err)
  421. }
  422. server := &recordingProviderGRPCServer{}
  423. grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(&tls.Config{
  424. MinVersion: tls.VersionTLS12,
  425. Certificates: []tls.Certificate{tlsCert},
  426. ClientCAs: caPool,
  427. ClientAuth: tls.RequireAndVerifyClientCert,
  428. })))
  429. pb.RegisterSecretStoreProviderServer(grpcServer, server)
  430. go func() {
  431. _ = grpcServer.Serve(lis)
  432. }()
  433. t.Cleanup(func() {
  434. grpcServer.Stop()
  435. _ = lis.Close()
  436. })
  437. return server, lis.Addr().String(), map[string][]byte{
  438. "ca.crt": caCert,
  439. "client.crt": clientCert,
  440. "client.key": clientKey,
  441. }
  442. }
  443. func assertProviderReference(t *testing.T, got *pb.ProviderReference, want esv1.ProviderReference, wantStoreRefKind string) {
  444. t.Helper()
  445. if got == nil {
  446. t.Fatal("expected provider reference to be set")
  447. }
  448. if got.ApiVersion != want.APIVersion || got.Kind != want.Kind || got.Name != want.Name || got.Namespace != want.Namespace {
  449. t.Fatalf("unexpected provider ref: got=%#v want=%#v", got, want)
  450. }
  451. if got.StoreRefKind != wantStoreRefKind {
  452. t.Fatalf("unexpected store ref kind: got=%q want=%q", got.StoreRefKind, wantStoreRefKind)
  453. }
  454. }
  455. func newProviderTLSArtifacts(t *testing.T, host string) (serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM []byte) {
  456. t.Helper()
  457. caKey, err := rsa.GenerateKey(rand.Reader, 2048)
  458. if err != nil {
  459. t.Fatalf("GenerateKey() error = %v", err)
  460. }
  461. caTemplate := &x509.Certificate{
  462. SerialNumber: big.NewInt(1),
  463. Subject: pkix.Name{CommonName: "provider-controller-test-ca"},
  464. NotBefore: time.Now().Add(-time.Hour),
  465. NotAfter: time.Now().Add(24 * time.Hour),
  466. KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
  467. BasicConstraintsValid: true,
  468. IsCA: true,
  469. }
  470. caDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey)
  471. if err != nil {
  472. t.Fatalf("CreateCertificate() error = %v", err)
  473. }
  474. caCert, err := x509.ParseCertificate(caDER)
  475. if err != nil {
  476. t.Fatalf("ParseCertificate() error = %v", err)
  477. }
  478. serverCertPEM, serverKeyPEM = newProviderSignedTLSCert(t, caCert, caKey, 2, host, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth})
  479. clientCertPEM, clientKeyPEM = newProviderSignedTLSCert(t, caCert, caKey, 3, host, []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth})
  480. caCertPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caDER})
  481. return serverCertPEM, serverKeyPEM, clientCertPEM, clientKeyPEM, caCertPEM
  482. }
  483. func newProviderSignedTLSCert(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, serial int64, host string, usages []x509.ExtKeyUsage) ([]byte, []byte) {
  484. t.Helper()
  485. key, err := rsa.GenerateKey(rand.Reader, 2048)
  486. if err != nil {
  487. t.Fatalf("GenerateKey() error = %v", err)
  488. }
  489. template := &x509.Certificate{
  490. SerialNumber: big.NewInt(serial),
  491. Subject: pkix.Name{CommonName: host},
  492. NotBefore: time.Now().Add(-time.Hour),
  493. NotAfter: time.Now().Add(24 * time.Hour),
  494. KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
  495. ExtKeyUsage: usages,
  496. }
  497. if ip := net.ParseIP(host); ip != nil {
  498. template.IPAddresses = []net.IP{ip}
  499. } else {
  500. template.DNSNames = []string{host}
  501. }
  502. der, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
  503. if err != nil {
  504. t.Fatalf("CreateCertificate() error = %v", err)
  505. }
  506. return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}),
  507. pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
  508. }