in istioctl/cmd/kubeinject.go [78:204]
func (e ExternalInjector) Inject(pod *corev1.Pod, deploymentNS string) ([]byte, error) {
cc := e.clientConfig
if cc == nil {
return nil, nil
}
var address string
if cc.URL != nil {
address = *cc.URL
}
var certPool *x509.CertPool
if len(cc.CABundle) > 0 {
certPool = x509.NewCertPool()
certPool.AppendCertsFromPEM(cc.CABundle)
} else {
var err error
certPool, err = x509.SystemCertPool()
if err != nil {
return nil, err
}
}
tlsClientConfig := &tls.Config{RootCAs: certPool}
client := http.Client{
Timeout: time.Second * 5,
Transport: &http.Transport{
TLSClientConfig: tlsClientConfig,
},
}
if cc.Service != nil {
svc, err := e.client.CoreV1().Services(cc.Service.Namespace).Get(context.Background(), cc.Service.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
namespace, selector, err := polymorphichelpers.SelectorsForObject(svc)
if err != nil {
if e.injectorAddress == "" {
return nil, fmt.Errorf("cannot attach to %T: %v", svc, err)
}
address = fmt.Sprintf("https://%s:%d%s", e.injectorAddress, *cc.Service.Port, *cc.Service.Path)
} else {
pod, err := GetFirstPod(e.client.CoreV1(), namespace, selector.String())
if err != nil {
return nil, err
}
webhookPort := cc.Service.Port
podPort := 15017
for _, v := range svc.Spec.Ports {
if v.Port == *webhookPort {
podPort = v.TargetPort.IntValue()
break
}
}
f, err := e.client.NewPortForwarder(pod.Name, pod.Namespace, "", 0, podPort)
if err != nil {
return nil, err
}
if err := f.Start(); err != nil {
return nil, err
}
address = fmt.Sprintf("https://%s%s", f.Address(), *cc.Service.Path)
defer func() {
f.Close()
f.WaitForStop()
}()
}
tlsClientConfig.ServerName = fmt.Sprintf("%s.%s.%s", cc.Service.Name, cc.Service.Namespace, "svc")
} else if isMCPAddr(address) {
var err error
client.Transport, err = mcpTransport(context.TODO(), client.Transport)
if err != nil {
return nil, err
}
}
podBytes, err := json.Marshal(pod)
if pod.Namespace != "" {
deploymentNS = pod.Namespace
}
if err != nil {
return nil, err
}
rev := &admission.AdmissionReview{
TypeMeta: metav1.TypeMeta{
APIVersion: admission.SchemeGroupVersion.String(),
Kind: "AdmissionReview",
},
Request: &admission.AdmissionRequest{
Object: runtime.RawExtension{Raw: podBytes},
Kind: metav1.GroupVersionKind{
Group: admission.GroupName,
Version: admission.SchemeGroupVersion.Version,
Kind: "AdmissionRequest",
},
Resource: metav1.GroupVersionResource{},
SubResource: "",
RequestKind: nil,
RequestResource: nil,
RequestSubResource: "",
Name: pod.Name,
Namespace: deploymentNS,
},
Response: nil,
}
revBytes, err := json.Marshal(rev)
if err != nil {
return nil, err
}
resp, err := client.Post(address, "application/json", bytes.NewBuffer(revBytes))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var obj runtime.Object
var ar *kube.AdmissionReview
out, _, err := deserializer.Decode(body, nil, obj)
if err != nil {
return nil, fmt.Errorf("could not decode body: %v", err)
}
ar, err = kube.AdmissionReviewKubeToAdapter(out)
if err != nil {
return nil, fmt.Errorf("could not decode object: %v", err)
}
return ar.Response.Patch, nil
}