diff --git a/apis/identity/v1alpha1/audittokenrequest_types.go b/apis/identity/v1alpha1/audittokenrequest_types.go new file mode 100644 index 0000000000..e42e9527c4 --- /dev/null +++ b/apis/identity/v1alpha1/audittokenrequest_types.go @@ -0,0 +1,62 @@ +/* +Copyright AppsCode Inc. and Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + ResourceKindAuditTokenRequest = "AuditTokenRequest" + ResourceAuditTokenRequest = "audittokenrequest" + ResourceAuditTokenRequests = "audittokenrequests" +) + +// +genclient +// +genclient:nonNamespaced +// +genclient:onlyVerbs=create +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=audittokenrequests,singular=audittokenrequest,scope=Cluster +type AuditTokenRequest struct { + metav1.TypeMeta `json:",inline"` + // Request describes the attributes for the nats credential request. + // +optional + Request *AuditTokenRequestRequest `json:"request,omitempty"` + // Response describes the attributes for the nats credential response. + // +optional + Response *AuditTokenRequestResponse `json:"response,omitempty"` +} + +type AuditTokenRequestRequest struct { + Features string `json:"features,omitempty"` + License []byte `json:"license,omitempty"` +} + +type AuditTokenRequestResponse struct { + NatsConfig `json:",inline"` + Credential []byte `json:"credential,omitempty"` +} + +type NatsConfig struct { + Subject string `json:"natsSubject"` + Server string `json:"natsServer"` +} + +func init() { + SchemeBuilder.Register(&AuditTokenRequest{}) +} diff --git a/apis/identity/v1alpha1/openapi_generated.go b/apis/identity/v1alpha1/openapi_generated.go index 2434aa4512..42e1423306 100644 --- a/apis/identity/v1alpha1/openapi_generated.go +++ b/apis/identity/v1alpha1/openapi_generated.go @@ -372,6 +372,9 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "kmodules.xyz/offshoot-api/api/v1.ServiceTemplateSpec": schema_kmodulesxyz_offshoot_api_api_v1_ServiceTemplateSpec(ref), "kmodules.xyz/offshoot-api/api/v1.Volume": schema_kmodulesxyz_offshoot_api_api_v1_Volume(ref), "kmodules.xyz/offshoot-api/api/v1.VolumeSource": schema_kmodulesxyz_offshoot_api_api_v1_VolumeSource(ref), + "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.AuditTokenRequest": schema_resource_metadata_apis_identity_v1alpha1_AuditTokenRequest(ref), + "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.AuditTokenRequestRequest": schema_resource_metadata_apis_identity_v1alpha1_AuditTokenRequestRequest(ref), + "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.AuditTokenRequestResponse": schema_resource_metadata_apis_identity_v1alpha1_AuditTokenRequestResponse(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.ClusterIdentity": schema_resource_metadata_apis_identity_v1alpha1_ClusterIdentity(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.ClusterIdentityList": schema_resource_metadata_apis_identity_v1alpha1_ClusterIdentityList(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.ControlPlaneInfo": schema_resource_metadata_apis_identity_v1alpha1_ControlPlaneInfo(ref), @@ -379,6 +382,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.InboxTokenRequestRequest": schema_resource_metadata_apis_identity_v1alpha1_InboxTokenRequestRequest(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.InboxTokenRequestResponse": schema_resource_metadata_apis_identity_v1alpha1_InboxTokenRequestResponse(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.KubernetesInfo": schema_resource_metadata_apis_identity_v1alpha1_KubernetesInfo(ref), + "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.NatsConfig": schema_resource_metadata_apis_identity_v1alpha1_NatsConfig(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.NodeInfo": schema_resource_metadata_apis_identity_v1alpha1_NodeInfo(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.NodeStats": schema_resource_metadata_apis_identity_v1alpha1_NodeStats(ref), "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.ProductInfo": schema_resource_metadata_apis_identity_v1alpha1_ProductInfo(ref), @@ -19663,6 +19667,103 @@ func schema_kmodulesxyz_offshoot_api_api_v1_VolumeSource(ref common.ReferenceCal } } +func schema_resource_metadata_apis_identity_v1alpha1_AuditTokenRequest(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "request": { + SchemaProps: spec.SchemaProps{ + Description: "Request describes the attributes for the nats credential request.", + Ref: ref("kmodules.xyz/resource-metadata/apis/identity/v1alpha1.AuditTokenRequestRequest"), + }, + }, + "response": { + SchemaProps: spec.SchemaProps{ + Description: "Response describes the attributes for the nats credential response.", + Ref: ref("kmodules.xyz/resource-metadata/apis/identity/v1alpha1.AuditTokenRequestResponse"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.AuditTokenRequestRequest", "kmodules.xyz/resource-metadata/apis/identity/v1alpha1.AuditTokenRequestResponse"}, + } +} + +func schema_resource_metadata_apis_identity_v1alpha1_AuditTokenRequestRequest(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "features": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "license": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "byte", + }, + }, + }, + }, + }, + } +} + +func schema_resource_metadata_apis_identity_v1alpha1_AuditTokenRequestResponse(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "natsSubject": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "natsServer": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "credential": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "byte", + }, + }, + }, + Required: []string{"natsSubject", "natsServer"}, + }, + }, + } +} + func schema_resource_metadata_apis_identity_v1alpha1_ClusterIdentity(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -19991,6 +20092,33 @@ func schema_resource_metadata_apis_identity_v1alpha1_KubernetesInfo(ref common.R } } +func schema_resource_metadata_apis_identity_v1alpha1_NatsConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "natsSubject": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "natsServer": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"natsSubject", "natsServer"}, + }, + }, + } +} + func schema_resource_metadata_apis_identity_v1alpha1_NodeInfo(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/apis/identity/v1alpha1/zz_generated.deepcopy.go b/apis/identity/v1alpha1/zz_generated.deepcopy.go index 580371d9dd..087f86b365 100644 --- a/apis/identity/v1alpha1/zz_generated.deepcopy.go +++ b/apis/identity/v1alpha1/zz_generated.deepcopy.go @@ -30,6 +30,84 @@ import ( version "k8s.io/apimachinery/pkg/version" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuditTokenRequest) DeepCopyInto(out *AuditTokenRequest) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Request != nil { + in, out := &in.Request, &out.Request + *out = new(AuditTokenRequestRequest) + (*in).DeepCopyInto(*out) + } + if in.Response != nil { + in, out := &in.Response, &out.Response + *out = new(AuditTokenRequestResponse) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuditTokenRequest. +func (in *AuditTokenRequest) DeepCopy() *AuditTokenRequest { + if in == nil { + return nil + } + out := new(AuditTokenRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AuditTokenRequest) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuditTokenRequestRequest) DeepCopyInto(out *AuditTokenRequestRequest) { + *out = *in + if in.License != nil { + in, out := &in.License, &out.License + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuditTokenRequestRequest. +func (in *AuditTokenRequestRequest) DeepCopy() *AuditTokenRequestRequest { + if in == nil { + return nil + } + out := new(AuditTokenRequestRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuditTokenRequestResponse) DeepCopyInto(out *AuditTokenRequestResponse) { + *out = *in + out.NatsConfig = in.NatsConfig + if in.Credential != nil { + in, out := &in.Credential, &out.Credential + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuditTokenRequestResponse. +func (in *AuditTokenRequestResponse) DeepCopy() *AuditTokenRequestResponse { + if in == nil { + return nil + } + out := new(AuditTokenRequestResponse) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterIdentity) DeepCopyInto(out *ClusterIdentity) { *out = *in @@ -242,6 +320,22 @@ func (in *KubernetesInfo) DeepCopy() *KubernetesInfo { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NatsConfig) DeepCopyInto(out *NatsConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NatsConfig. +func (in *NatsConfig) DeepCopy() *NatsConfig { + if in == nil { + return nil + } + out := new(NatsConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NodeInfo) DeepCopyInto(out *NodeInfo) { *out = *in diff --git a/client/clientset/versioned/typed/identity/v1alpha1/audittokenrequest.go b/client/clientset/versioned/typed/identity/v1alpha1/audittokenrequest.go new file mode 100644 index 0000000000..69614801ef --- /dev/null +++ b/client/clientset/versioned/typed/identity/v1alpha1/audittokenrequest.go @@ -0,0 +1,64 @@ +/* +Copyright AppsCode Inc. and Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + rest "k8s.io/client-go/rest" + v1alpha1 "kmodules.xyz/resource-metadata/apis/identity/v1alpha1" + scheme "kmodules.xyz/resource-metadata/client/clientset/versioned/scheme" +) + +// AuditTokenRequestsGetter has a method to return a AuditTokenRequestInterface. +// A group's client should implement this interface. +type AuditTokenRequestsGetter interface { + AuditTokenRequests() AuditTokenRequestInterface +} + +// AuditTokenRequestInterface has methods to work with AuditTokenRequest resources. +type AuditTokenRequestInterface interface { + Create(ctx context.Context, auditTokenRequest *v1alpha1.AuditTokenRequest, opts v1.CreateOptions) (*v1alpha1.AuditTokenRequest, error) + AuditTokenRequestExpansion +} + +// auditTokenRequests implements AuditTokenRequestInterface +type auditTokenRequests struct { + client rest.Interface +} + +// newAuditTokenRequests returns a AuditTokenRequests +func newAuditTokenRequests(c *IdentityV1alpha1Client) *auditTokenRequests { + return &auditTokenRequests{ + client: c.RESTClient(), + } +} + +// Create takes the representation of a auditTokenRequest and creates it. Returns the server's representation of the auditTokenRequest, and an error, if there is any. +func (c *auditTokenRequests) Create(ctx context.Context, auditTokenRequest *v1alpha1.AuditTokenRequest, opts v1.CreateOptions) (result *v1alpha1.AuditTokenRequest, err error) { + result = &v1alpha1.AuditTokenRequest{} + err = c.client.Post(). + Resource("audittokenrequests"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(auditTokenRequest). + Do(ctx). + Into(result) + return +} diff --git a/client/clientset/versioned/typed/identity/v1alpha1/fake/fake_audittokenrequest.go b/client/clientset/versioned/typed/identity/v1alpha1/fake/fake_audittokenrequest.go new file mode 100644 index 0000000000..ac674cfb08 --- /dev/null +++ b/client/clientset/versioned/typed/identity/v1alpha1/fake/fake_audittokenrequest.go @@ -0,0 +1,46 @@ +/* +Copyright AppsCode Inc. and Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + testing "k8s.io/client-go/testing" + v1alpha1 "kmodules.xyz/resource-metadata/apis/identity/v1alpha1" +) + +// FakeAuditTokenRequests implements AuditTokenRequestInterface +type FakeAuditTokenRequests struct { + Fake *FakeIdentityV1alpha1 +} + +var audittokenrequestsResource = v1alpha1.SchemeGroupVersion.WithResource("audittokenrequests") + +var audittokenrequestsKind = v1alpha1.SchemeGroupVersion.WithKind("AuditTokenRequest") + +// Create takes the representation of a auditTokenRequest and creates it. Returns the server's representation of the auditTokenRequest, and an error, if there is any. +func (c *FakeAuditTokenRequests) Create(ctx context.Context, auditTokenRequest *v1alpha1.AuditTokenRequest, opts v1.CreateOptions) (result *v1alpha1.AuditTokenRequest, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(audittokenrequestsResource, auditTokenRequest), &v1alpha1.AuditTokenRequest{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.AuditTokenRequest), err +} diff --git a/client/clientset/versioned/typed/identity/v1alpha1/fake/fake_identity_client.go b/client/clientset/versioned/typed/identity/v1alpha1/fake/fake_identity_client.go index 3cfecfa9e2..e730fcca84 100644 --- a/client/clientset/versioned/typed/identity/v1alpha1/fake/fake_identity_client.go +++ b/client/clientset/versioned/typed/identity/v1alpha1/fake/fake_identity_client.go @@ -28,6 +28,10 @@ type FakeIdentityV1alpha1 struct { *testing.Fake } +func (c *FakeIdentityV1alpha1) AuditTokenRequests() v1alpha1.AuditTokenRequestInterface { + return &FakeAuditTokenRequests{c} +} + func (c *FakeIdentityV1alpha1) ClusterIdentities(namespace string) v1alpha1.ClusterIdentityInterface { return &FakeClusterIdentities{c, namespace} } diff --git a/client/clientset/versioned/typed/identity/v1alpha1/generated_expansion.go b/client/clientset/versioned/typed/identity/v1alpha1/generated_expansion.go index 2759be69e2..9c3fed547c 100644 --- a/client/clientset/versioned/typed/identity/v1alpha1/generated_expansion.go +++ b/client/clientset/versioned/typed/identity/v1alpha1/generated_expansion.go @@ -18,6 +18,8 @@ limitations under the License. package v1alpha1 +type AuditTokenRequestExpansion interface{} + type ClusterIdentityExpansion interface{} type InboxTokenRequestExpansion interface{} diff --git a/client/clientset/versioned/typed/identity/v1alpha1/identity_client.go b/client/clientset/versioned/typed/identity/v1alpha1/identity_client.go index 8f05d4680f..d83e8bb659 100644 --- a/client/clientset/versioned/typed/identity/v1alpha1/identity_client.go +++ b/client/clientset/versioned/typed/identity/v1alpha1/identity_client.go @@ -28,6 +28,7 @@ import ( type IdentityV1alpha1Interface interface { RESTClient() rest.Interface + AuditTokenRequestsGetter ClusterIdentitiesGetter InboxTokenRequestsGetter SelfSubjectNamespaceAccessReviewsGetter @@ -38,6 +39,10 @@ type IdentityV1alpha1Client struct { restClient rest.Interface } +func (c *IdentityV1alpha1Client) AuditTokenRequests() AuditTokenRequestInterface { + return newAuditTokenRequests(c) +} + func (c *IdentityV1alpha1Client) ClusterIdentities(namespace string) ClusterIdentityInterface { return newClusterIdentities(c, namespace) } diff --git a/pkg/identity/b3.go b/pkg/identity/b3.go index d671bf6822..18e3c685e4 100644 --- a/pkg/identity/b3.go +++ b/pkg/identity/b3.go @@ -17,6 +17,7 @@ limitations under the License. package identity import ( + "bytes" "crypto/tls" "crypto/x509" "encoding/pem" @@ -51,6 +52,17 @@ type Client struct { kc client.Reader } +// NewDefaultClient returns a Client wired to the production appscode.com +// endpoint with no token and no controller-runtime client. It is intended +// for one-shot callers (e.g. audit) that only need to hit the public +// register endpoint and supply the cluster UID themselves; methods that +// touch c.kc will panic on a Client created this way. +func NewDefaultClient() *Client { + return &Client{ + client: http.DefaultClient, + } +} + func NewClient(baseURL, token string, caCert []byte, kc client.Reader) (*Client, error) { c := &Client{ baseURL: baseURL, @@ -200,6 +212,102 @@ func (c *Client) GetToken() (*identityapi.InboxTokenRequestResponse, error) { return tokenResponse, nil } +// auditRegisterOptions mirrors the payload accepted by the appscode register +// endpoint (api/v1/register). It is duplicated here so that resource-metadata +// does not need to vendor the full license-verifier package. +type auditRegisterOptions struct { + ClusterUID string `json:"clusterUID"` + Features string `json:"features"` + CACert []byte `json:"caCert,omitempty"` + License []byte `json:"license"` +} + +// GetAuditToken resolves the cluster UID via c.kc and then calls +// GetAuditTokenForCluster. Use GetAuditTokenForCluster directly when +// the cluster UID is already known and there is no controller-runtime client +// available. +func (c *Client) GetAuditToken(features string, license []byte) (*identityapi.AuditTokenRequestResponse, error) { + md, err := clustermeta.ClusterMetadata(c.kc) + if err != nil { + return nil, err + } + return c.GetAuditTokenForCluster(md.UID, features, license) +} + +// GetAuditTokenForCluster posts the supplied license to the appscode +// Register endpoint (api/v1/register) and returns the issued NATS +// subject/server/credential. It does not touch c.kc, so it is safe to call +// on a Client constructed without one. +func (c *Client) GetAuditTokenForCluster(clusterUID, features string, license []byte) (*identityapi.AuditTokenRequestResponse, error) { + if features == "" { + features = info.ProductName + } + + opts := auditRegisterOptions{ + ClusterUID: clusterUID, + Features: features, + CACert: []byte(info.LicenseCA), + License: license, + } + data, err := json.Marshal(opts) + if err != nil { + return nil, err + } + + endpoint, err := info.RegistrationAPIEndpoint(c.baseURL) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewReader(data)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + if c.token != "" { + req.Header.Add("Authorization", "Bearer "+c.token) + } + if klog.V(8).Enabled() { + command, _ := http2curl.GetCurlCommand(req) + klog.V(8).Infoln(command.String()) + } + + resp, err := c.client.Do(req) + if err != nil { + var ce *tls.CertificateVerificationError + if errors.As(err, &ce) { + klog.ErrorS(err, "UnverifiedCertificates") + for _, cert := range ce.UnverifiedCertificates { + klog.Errorln(string(encodeCertPEM(cert))) + } + } + return nil, err + } + defer resp.Body.Close() // nolint:errcheck + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, apierrors.NewGenericServerResponse( + resp.StatusCode, + http.MethodPost, + schema.GroupResource{Group: identityapi.GroupName, Resource: identityapi.ResourceAuditTokenRequests}, + "", + string(body), + 0, + false, + ) + } + + out := &identityapi.AuditTokenRequestResponse{} + if err = json.Unmarshal(body, out); err != nil { + return nil, err + } + return out, nil +} + const SelfName = "self" func (c *Client) GetIdentity() (*identityapi.ClusterIdentity, error) {