istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/writer/ztunnel/configdump/certificates.go (about) 1 // Copyright Istio Authors 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package configdump 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "math/big" 21 "strings" 22 "text/tabwriter" 23 "time" 24 25 "sigs.k8s.io/yaml" 26 27 "istio.io/istio/pkg/log" 28 ) 29 30 // PrintSecretDump prints just the secret config dump to the ConfigWriter stdout 31 func (c *ConfigWriter) PrintSecretDump(outputFormat string) error { 32 if c.ztunnelDump == nil { 33 return fmt.Errorf("config writer has not been primed") 34 } 35 secretDump := c.ztunnelDump.Certificates 36 out, err := json.MarshalIndent(secretDump, "", " ") 37 if err != nil { 38 return fmt.Errorf("failed to marshal secrets dump: %v", err) 39 } 40 if outputFormat == "yaml" { 41 if out, err = yaml.JSONToYAML(out); err != nil { 42 return err 43 } 44 } 45 fmt.Fprintln(c.Stdout, string(out)) 46 return nil 47 } 48 49 // PrintSecretSummary prints a summary of dynamic active secrets from the config dump 50 func (c *ConfigWriter) PrintSecretSummary() error { 51 if c.ztunnelDump == nil { 52 return fmt.Errorf("config writer has not been primed") 53 } 54 secretDump := c.ztunnelDump.Certificates 55 w := new(tabwriter.Writer).Init(c.Stdout, 0, 8, 5, ' ', 0) 56 fmt.Fprintln(w, "CERTIFICATE NAME\tTYPE\tSTATUS\tVALID CERT\tSERIAL NUMBER\tNOT AFTER\tNOT BEFORE") 57 58 for _, secret := range secretDump { 59 if strings.Contains(secret.State, "Unavailable") { 60 secret.State = "Unavailable" 61 } 62 if len(secret.CertChain) == 0 { 63 fmt.Fprintf(w, "%v\t%v\t%v\t%v\t%v\t%v\t%v\n", 64 secret.Identity, valueOrNA(""), secret.State, false, valueOrNA(""), valueOrNA(""), valueOrNA("")) 65 } else { 66 for i, ca := range secret.CertChain { 67 t := "Intermediate" 68 if i == 0 { 69 t = "Leaf" 70 } else if i == len(secret.CertChain)-1 { 71 t = "Root" 72 } 73 n := new(big.Int) 74 n, _ = n.SetString(ca.SerialNumber, 10) 75 fmt.Fprintf(w, "%v\t%v\t%v\t%v\t%x\t%v\t%v\n", 76 secret.Identity, t, secret.State, certNotExpired(ca), n, valueOrNA(ca.ExpirationTime), valueOrNA(ca.ValidFrom)) 77 } 78 } 79 } 80 return w.Flush() 81 } 82 83 func valueOrNA(value string) string { 84 if value == "" { 85 return "NA" 86 } 87 return value 88 } 89 90 func certNotExpired(cert *Cert) bool { 91 // case where cert state is in either Initializing or Unavailable state 92 if cert.ExpirationTime == "" && cert.ValidFrom == "" { 93 return false 94 } 95 today := time.Now() 96 expDate, err := time.Parse(time.RFC3339, cert.ExpirationTime) 97 if err != nil { 98 log.Errorf("certificate timestamp (%v) could not be parsed: %v", cert.ExpirationTime, err) 99 return false 100 } 101 fromDate, err := time.Parse(time.RFC3339, cert.ValidFrom) 102 if err != nil { 103 log.Errorf("certificate timestamp (%v) could not be parsed: %v", cert.ValidFrom, err) 104 return false 105 } 106 if today.After(fromDate) && today.Before(expDate) { 107 return true 108 } 109 return false 110 }