diff --git a/apis/compute/v1beta1/computefirewallpolicyrule_types.go b/apis/compute/v1beta1/computefirewallpolicyrule_types.go index 6a4cedfcac..da8d6eac6e 100644 --- a/apis/compute/v1beta1/computefirewallpolicyrule_types.go +++ b/apis/compute/v1beta1/computefirewallpolicyrule_types.go @@ -20,6 +20,15 @@ import ( refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" commonv1alpha1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/common/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + ComputeFirewallPolicyRuleGVK = schema.GroupVersionKind{ + Group: SchemeGroupVersion.Group, + Version: SchemeGroupVersion.Version, + Kind: "ComputeFirewallPolicyRule", + } ) // +kcc:proto=google.cloud.compute.v1.FirewallPolicyRuleMatcherLayer4Config diff --git a/pkg/controller/direct/compute/firewallpolicyrule/client.go b/pkg/controller/direct/compute/firewallpolicyrule/client.go new file mode 100644 index 0000000000..cbcc0207ae --- /dev/null +++ b/pkg/controller/direct/compute/firewallpolicyrule/client.go @@ -0,0 +1,88 @@ +// Copyright 2024 Google LLC +// +// 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 firewallpolicyrule + +import ( + "context" + "fmt" + "net/http" + + api "cloud.google.com/go/compute/apiv1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/config" + "google.golang.org/api/option" +) + +type gcpClient struct { + config config.ControllerConfig +} + +func newGCPClient(ctx context.Context, config *config.ControllerConfig) (*gcpClient, error) { + gcpClient := &gcpClient{ + config: *config, + } + return gcpClient, nil +} + +func (m *gcpClient) options() ([]option.ClientOption, error) { + var opts []option.ClientOption + if m.config.UserAgent != "" { + opts = append(opts, option.WithUserAgent(m.config.UserAgent)) + } + if m.config.HTTPClient != nil { + // TODO: Set UserAgent in this scenario (error is: WithHTTPClient is incompatible with gRPC dial options) + + httpClient := &http.Client{} + *httpClient = *m.config.HTTPClient + httpClient.Transport = &optionsRoundTripper{ + config: m.config, + inner: m.config.HTTPClient.Transport, + } + opts = append(opts, option.WithHTTPClient(httpClient)) + } + if m.config.UserProjectOverride && m.config.BillingProject != "" { + opts = append(opts, option.WithQuotaProject(m.config.BillingProject)) + } + + // TODO: support endpoints? + // if m.config.Endpoint != "" { + // opts = append(opts, option.WithEndpoint(m.config.Endpoint)) + // } + + return opts, nil +} + +type optionsRoundTripper struct { + config config.ControllerConfig + inner http.RoundTripper +} + +func (m *optionsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if m.config.UserAgent != "" { + req.Header.Set("User-Agent", m.config.UserAgent) + } + return m.inner.RoundTrip(req) +} + +func (m *gcpClient) firewallPoliciesClient(ctx context.Context) (*api.FirewallPoliciesClient, error) { + opts, err := m.options() + if err != nil { + return nil, err + } + client, err := api.NewFirewallPoliciesRESTClient(ctx, opts...) + if err != nil { + return nil, fmt.Errorf("building FirewallPolicy client: %w", err) + } + return client, err +} diff --git a/pkg/controller/direct/compute/firewallpolicyrule/firewallpolicyrule_controller.go b/pkg/controller/direct/compute/firewallpolicyrule/firewallpolicyrule_controller.go new file mode 100644 index 0000000000..3378c0865e --- /dev/null +++ b/pkg/controller/direct/compute/firewallpolicyrule/firewallpolicyrule_controller.go @@ -0,0 +1,295 @@ +// Copyright 2024 Google LLC +// +// 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 firewallpolicyrule + +import ( + "context" + "fmt" + + gcp "cloud.google.com/go/compute/apiv1" + computepb "cloud.google.com/go/compute/apiv1/computepb" + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/compute/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/config" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/directbase" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/registry" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ctrlName = "firewallpolicyrule-controller" + +func init() { + registry.RegisterModel(krm.ComputeFirewallPolicyRuleGVK, NewFirewallPolicyRuleModel) +} + +func NewFirewallPolicyRuleModel(ctx context.Context, config *config.ControllerConfig) (directbase.Model, error) { + return &firewallPolicyRuleModel{config: config}, nil +} + +type firewallPolicyRuleModel struct { + config *config.ControllerConfig +} + +// model implements the Model interface. +var _ directbase.Model = &firewallPolicyRuleModel{} + +type firewallPolicyRuleAdapter struct { + firewallPolicy string + priority int64 + firewallPoliciesClient *gcp.FirewallPoliciesClient + desired *krm.ComputeFirewallPolicyRule + actual *computepb.FirewallPolicyRule + reader client.Reader +} + +var _ directbase.Adapter = &firewallPolicyRuleAdapter{} + +func (m *firewallPolicyRuleModel) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) { + obj := &krm.ComputeFirewallPolicyRule{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &obj); err != nil { + return nil, fmt.Errorf("error converting to %T: %w", obj, err) + } + + // Set label managed-by-cnrm: true + obj.ObjectMeta.Labels["managed-by-cnrm"] = "true" + + // Get firewall policy + firewallPolicyRef, err := ResolveComputeFirewallPolicy(ctx, reader, obj, obj.Spec.FirewallPolicyRef) + if err != nil { + return nil, err + + } + obj.Spec.FirewallPolicyRef.External = firewallPolicyRef.External + firewallPolicy := obj.Spec.FirewallPolicyRef.External + + // Get priority + priority := obj.Spec.Priority + + firewallPolicyRuleAdapter := &firewallPolicyRuleAdapter{ + firewallPolicy: firewallPolicy, + priority: priority, + desired: obj, + reader: reader, + } + + // Get GCP client + gcpClient, err := newGCPClient(ctx, m.config) + if err != nil { + return nil, fmt.Errorf("building gcp client: %w", err) + } + + firewallPoliciesClient, err := gcpClient.firewallPoliciesClient(ctx) + if err != nil { + return nil, err + } + firewallPolicyRuleAdapter.firewallPoliciesClient = firewallPoliciesClient + + return firewallPolicyRuleAdapter, nil +} + +func (m *firewallPolicyRuleModel) AdapterForURL(ctx context.Context, url string) (directbase.Adapter, error) { + // TODO: Support URLs + return nil, nil +} + +func (a *firewallPolicyRuleAdapter) Find(ctx context.Context) (bool, error) { + log := klog.FromContext(ctx).WithName(ctrlName) + log.V(2).Info("getting ComputeFirewallPolicyRule", "priority", a.priority) + + firewallPolicyRule, err := a.get(ctx) + if err != nil { + // When a certain rule does not exist, the error has code 400(invalid) instead of 404(not found) + // example error message: + // "Invalid value for field 'priority': '9000'. The firewall policy does not contain a rule at priority 9000.", + if direct.IsInvalidValue(err) { + return false, nil + } + return false, fmt.Errorf("getting ComputeFirewallPolicyRule %d: %w", a.priority, err) + } + a.actual = firewallPolicyRule + return true, nil +} + +func (a *firewallPolicyRuleAdapter) Create(ctx context.Context, createOp *directbase.CreateOperation) error { + u := createOp.GetUnstructured() + + log := klog.FromContext(ctx).WithName(ctrlName) + log.V(2).Info("creating ComputeFirewallPolicyRule", "priority", a.priority) + mapCtx := &direct.MapContext{} + + desired := a.desired.DeepCopy() + + firewallPolicyRule := ComputeFirewallPolicyRuleSpec_ToProto(mapCtx, &desired.Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + firewallPolicyRule.Priority = direct.LazyPtr(int32(a.priority)) + + req := &computepb.AddRuleFirewallPolicyRequest{ + FirewallPolicyRuleResource: firewallPolicyRule, + FirewallPolicy: a.firewallPolicy, + } + op, err := a.firewallPoliciesClient.AddRule(ctx, req) + + if err != nil { + return fmt.Errorf("creating ComputeFirewallPolicyRule %d: %w", a.priority, err) + } + if !op.Done() { + err = op.Wait(ctx) + if err != nil { + return fmt.Errorf("waiting ComputeFirewallPolicyRule %d create failed: %w", a.priority, err) + } + } + log.V(2).Info("successfully created ComputeFirewallPolicyRule", "priority", a.priority) + + // Get the created resource + created := &computepb.FirewallPolicyRule{} + created, err = a.get(ctx) + if err != nil { + return fmt.Errorf("getting ComputeFirewallPolicyRule %d: %w", a.priority, err) + } + + status := &krm.ComputeFirewallPolicyRuleStatus{ + RuleTupleCount: direct.PtrTo(int64(*created.RuleTupleCount)), + } + return setStatus(u, status) +} + +func (a *firewallPolicyRuleAdapter) Update(ctx context.Context, updateOp *directbase.UpdateOperation) error { + u := updateOp.GetUnstructured() + var err error + + log := klog.FromContext(ctx).WithName(ctrlName) + log.V(2).Info("updating ComputeFirewallPolicyRule", "priority", a.priority) + mapCtx := &direct.MapContext{} + + desired := a.desired.DeepCopy() + firewallPolicyRule := ComputeFirewallPolicyRuleSpec_ToProto(mapCtx, &desired.Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + firewallPolicyRule.Priority = direct.LazyPtr(int32(a.priority)) + + op := &gcp.Operation{} + updated := &computepb.FirewallPolicyRule{} + + updateReq := &computepb.PatchRuleFirewallPolicyRequest{ + FirewallPolicyRuleResource: firewallPolicyRule, + FirewallPolicy: a.firewallPolicy, + Priority: direct.PtrTo(int32(a.priority)), + } + op, err = a.firewallPoliciesClient.PatchRule(ctx, updateReq) + if err != nil { + return fmt.Errorf("updating ComputeFirewallPolicyRule %d: %w", a.priority, err) + } + if !op.Done() { + err = op.Wait(ctx) + if err != nil { + return fmt.Errorf("waiting ComputeFirewallPolicyRule %d update failed: %w", a.priority, err) + } + } + log.V(2).Info("successfully updated ComputeFirewallPolicyRule", "priority", a.priority) + + // Get the updated resource + updated, err = a.get(ctx) + if err != nil { + return fmt.Errorf("getting ComputeFirewallPolicyRule %d: %w", a.priority, err) + } + + status := &krm.ComputeFirewallPolicyRuleStatus{ + RuleTupleCount: direct.PtrTo(int64(*updated.RuleTupleCount)), + } + return setStatus(u, status) +} + +func (a *firewallPolicyRuleAdapter) Export(ctx context.Context) (*unstructured.Unstructured, error) { + if a.actual == nil { + return nil, fmt.Errorf("firewallPolicyRule %d not found", a.priority) + } + + mc := &direct.MapContext{} + spec := ComputeFirewallPolicyRuleSpec_FromProto(mc, a.actual) + specObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(spec) + if err != nil { + return nil, fmt.Errorf("error converting firewallPolicyRule spec to unstructured: %w", err) + } + + u := &unstructured.Unstructured{ + Object: make(map[string]interface{}), + } + u.SetGroupVersionKind(krm.ComputeFirewallPolicyRuleGVK) + + if err := unstructured.SetNestedField(u.Object, specObj, "spec"); err != nil { + return nil, fmt.Errorf("setting spec: %w", err) + } + + return u, nil +} + +// Delete implements the Adapter interface. +func (a *firewallPolicyRuleAdapter) Delete(ctx context.Context, deleteOp *directbase.DeleteOperation) (bool, error) { + + log := klog.FromContext(ctx).WithName(ctrlName) + log.V(2).Info("deleting ComputeFirewallPolicyRule", "priority", a.priority) + + var err error + op := &gcp.Operation{} + req := &computepb.RemoveRuleFirewallPolicyRequest{ + FirewallPolicy: a.firewallPolicy, + Priority: direct.PtrTo(int32(a.priority)), + } + op, err = a.firewallPoliciesClient.RemoveRule(ctx, req) + + if err != nil { + return false, fmt.Errorf("deleting ComputeFirewallPolicyRule %d: %w", a.priority, err) + } + if !op.Done() { + err = op.Wait(ctx) + if err != nil { + return false, fmt.Errorf("waiting ComputeFirewallPolicyRule %d delete failed: %w", a.priority, err) + } + } + log.V(2).Info("successfully deleted ComputeFirewallPolicyRule", "priority", a.priority) + return true, nil +} + +func (a *firewallPolicyRuleAdapter) get(ctx context.Context) (*computepb.FirewallPolicyRule, error) { + getReq := &computepb.GetRuleFirewallPolicyRequest{ + FirewallPolicy: a.firewallPolicy, + Priority: direct.PtrTo(int32(a.priority)), + } + return a.firewallPoliciesClient.GetRule(ctx, getReq) +} + +func setStatus(u *unstructured.Unstructured, typedStatus any) error { + status, err := runtime.DefaultUnstructuredConverter.ToUnstructured(typedStatus) + if err != nil { + return fmt.Errorf("error converting status to unstructured: %w", err) + } + + old, _, _ := unstructured.NestedMap(u.Object, "status") + if old != nil { + status["conditions"] = old["conditions"] + status["observedGeneration"] = old["observedGeneration"] + status["externalRef"] = old["externalRef"] + } + + u.Object["status"] = status + + return nil +} diff --git a/pkg/controller/direct/compute/firewallpolicyrule/firewallpolicyrule_externalresource.go b/pkg/controller/direct/compute/firewallpolicyrule/firewallpolicyrule_externalresource.go new file mode 100644 index 0000000000..fc8edc4366 --- /dev/null +++ b/pkg/controller/direct/compute/firewallpolicyrule/firewallpolicyrule_externalresource.go @@ -0,0 +1,26 @@ +/* +Copyright 2024. + +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 firewallpolicyrule + +const ( + serviceDomain = "//compute.googleapis.com" +) + +type FirewallPolicyRuleIdentity struct { + firewallPolicy string + priority int64 +} diff --git a/pkg/controller/direct/compute/firewallpolicyrule/refs.go b/pkg/controller/direct/compute/firewallpolicyrule/refs.go new file mode 100644 index 0000000000..d82f8bc1dd --- /dev/null +++ b/pkg/controller/direct/compute/firewallpolicyrule/refs.go @@ -0,0 +1,84 @@ +// Copyright 2024 Google LLC +// +// 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 firewallpolicyrule + +import ( + "context" + "fmt" + + refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func ResolveComputeFirewallPolicy(ctx context.Context, reader client.Reader, src client.Object, ref *refs.ComputeFirewallPolicyRef) (*refs.ComputeFirewallPolicyRef, error) { + if ref == nil { + return nil, nil + } + + if ref.External != "" { + if ref.Name != "" { + return nil, fmt.Errorf("cannot specify both name and external on reference") + } + return ref, nil + } + + if ref.Name == "" { + return nil, fmt.Errorf("must specify either name or external on reference") + } + + key := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + if key.Namespace == "" { + key.Namespace = src.GetNamespace() + } + + computeFirwallPolicy, err := resolveResourceName(ctx, reader, key, schema.GroupVersionKind{ + Group: "compute.cnrm.cloud.google.com", + Version: "v1beta1", + Kind: "ComputeFirewallPolicy", + }) + + if err != nil { + return nil, err + } + + resourceID, err := refs.GetResourceID(computeFirwallPolicy) + if err != nil { + return nil, err + } + + return &refs.ComputeFirewallPolicyRef{ + External: fmt.Sprintf("%s", resourceID)}, nil +} + +func resolveResourceName(ctx context.Context, reader client.Reader, key client.ObjectKey, gvk schema.GroupVersionKind) (*unstructured.Unstructured, error) { + resource := &unstructured.Unstructured{} + resource.SetGroupVersionKind(gvk) + if err := reader.Get(ctx, key, resource); err != nil { + if apierrors.IsNotFound(err) { + return nil, k8s.NewReferenceNotFoundError(resource.GroupVersionKind(), key) + } + return nil, fmt.Errorf("error reading referenced %v %v: %w", gvk.Kind, key, err) + } + + return resource, nil +} diff --git a/pkg/controller/direct/maputils.go b/pkg/controller/direct/maputils.go index 46bb0c6b15..f6643ae63e 100644 --- a/pkg/controller/direct/maputils.go +++ b/pkg/controller/direct/maputils.go @@ -193,6 +193,11 @@ func IsNotFound(err error) bool { return HasHTTPCode(err, 404) } +// IsInvalidValue returns true if the given error is an HTTP 400. +func IsInvalidValue(err error) bool { + return HasHTTPCode(err, 400) +} + // HasHTTPCode returns true if the given error is an HTTP response with the given code. func HasHTTPCode(err error, code int) bool { if err == nil { diff --git a/pkg/test/resourcefixture/testdata/basic/compute/v1beta1/computefirewallpolicyrule/_generated_object_computefirewallpolicyrule.golden.yaml b/pkg/test/resourcefixture/testdata/basic/compute/v1beta1/computefirewallpolicyrule/_generated_object_computefirewallpolicyrule.golden.yaml new file mode 100644 index 0000000000..15fc632b25 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/compute/v1beta1/computefirewallpolicyrule/_generated_object_computefirewallpolicyrule.golden.yaml @@ -0,0 +1,33 @@ +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeFirewallPolicyRule +metadata: + annotations: + cnrm.cloud.google.com/management-conflict-prevention-policy: none + finalizers: + - cnrm.cloud.google.com/finalizer + - cnrm.cloud.google.com/deletion-defender + generation: 2 + labels: + cnrm-test: "true" + name: firewallpolicyrule-${uniqueId} + namespace: ${uniqueId} +spec: + action: allow + direction: INGRESS + firewallPolicyRef: + name: firewallpolicyrule-${uniqueId} + match: + layer4Configs: + - ipProtocol: tcp + srcIPRanges: + - 10.100.0.1/32 + priority: 9000 +status: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: The resource is up to date + reason: UpToDate + status: "True" + type: Ready + observedGeneration: 2 + ruleTupleCount: 2 diff --git a/pkg/test/resourcefixture/testdata/basic/compute/v1beta1/computefirewallpolicyrule/_http.log b/pkg/test/resourcefixture/testdata/basic/compute/v1beta1/computefirewallpolicyrule/_http.log new file mode 100644 index 0000000000..5d0391a394 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/compute/v1beta1/computefirewallpolicyrule/_http.log @@ -0,0 +1,721 @@ +POST https://www.googleapis.com/compute/v1/locations/global/firewallPolicies?alt=json&parentId=organizations%2F128653134652 +Content-Type: application/json +User-Agent: kcc/controller-manager DeclarativeClientLib/0.0.1 + +{ + "description": "A basic folder firewall policy", + "parent": "organizations/${organizationID}", + "shortName": "firewallpolicy-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "createFirewallPolicy", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "user": "user@example.com" +} + +--- + +GET https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}?alt=json&parentId=organizations%2F128653134652 +Content-Type: application/json +User-Agent: kcc/controller-manager DeclarativeClientLib/0.0.1 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "createFirewallPolicy", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012?alt=json +Content-Type: application/json +User-Agent: kcc/controller-manager DeclarativeClientLib/0.0.1 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "description": "A basic folder firewall policy", + "displayName": "firewallpolicy-${uniqueId}", + "fingerprint": "abcdef0123A=", + "id": "000000000000000000000", + "kind": "compute#firewallPolicy", + "name": "774029050012", + "parent": "organizations/${organizationID}", + "ruleTupleCount": 8, + "rules": [ + { + "action": "goto_next", + "description": "default egress rule ipv6", + "direction": "EGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "destIpRanges": [ + "::/0" + ], + "layer4Configs": [ + { + "ipProtocol": "all" + } + ] + }, + "priority": 2147483644, + "ruleTupleCount": 2 + }, + { + "action": "goto_next", + "description": "default ingress rule ipv6", + "direction": "INGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "layer4Configs": [ + { + "ipProtocol": "all" + } + ], + "srcIpRanges": [ + "::/0" + ] + }, + "priority": 2147483645, + "ruleTupleCount": 2 + }, + { + "action": "goto_next", + "description": "default egress rule", + "direction": "EGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "destIpRanges": [ + "0.0.0.0/0" + ], + "layer4Configs": [ + { + "ipProtocol": "all" + } + ] + }, + "priority": 2147483646, + "ruleTupleCount": 2 + }, + { + "action": "goto_next", + "description": "default ingress rule", + "direction": "INGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "layer4Configs": [ + { + "ipProtocol": "all" + } + ], + "srcIpRanges": [ + "0.0.0.0/0" + ] + }, + "priority": 2147483647, + "ruleTupleCount": 2 + } + ], + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/774029050012", + "shortName": "firewallpolicy-${uniqueId}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/getRule?priority=9000 +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: firewall_policy=774029050012 + +400 Bad Request +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 400, + "errors": [ + { + "domain": "global", + "message": "Invalid value for field 'priority': '9000'. The firewall policy does not contain a rule at priority 9000.", + "reason": "invalid" + } + ], + "message": "Invalid value for field 'priority': '9000'. The firewall policy does not contain a rule at priority 9000." + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/addRule +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: firewall_policy=774029050012 + +{ + "action": "deny", + "direction": "INGRESS", + "match": { + "layer4Configs": [ + { + "ipProtocol": "tcp" + } + ], + "srcIpRanges": [ + "10.100.0.1/32" + ] + }, + "priority": 9000 +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "addFirewallRuleToFirewallPolicy", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/locations/global/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: operation=${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "addFirewallRuleToFirewallPolicy", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/getRule?priority=9000 +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: firewall_policy=774029050012 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "action": "deny", + "description": "", + "direction": "INGRESS", + "kind": "compute#firewallPolicyRule", + "match": { + "layer4Configs": [ + { + "ipProtocol": "tcp" + } + ], + "srcIpRanges": [ + "10.100.0.1/32" + ] + }, + "priority": 9000, + "ruleTupleCount": 2 +} + +--- + +POST https://compute.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/patchRule?priority=9000 +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: firewall_policy=774029050012 + +{ + "action": "allow", + "direction": "INGRESS", + "match": { + "layer4Configs": [ + { + "ipProtocol": "tcp" + } + ], + "srcIpRanges": [ + "10.100.0.1/32" + ] + }, + "priority": 9000 +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "patchFirewallRuleInFirewallPolicy", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/locations/global/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: operation=${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "patchFirewallRuleInFirewallPolicy", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/getRule?priority=9000 +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: firewall_policy=774029050012 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "action": "allow", + "description": "", + "direction": "INGRESS", + "kind": "compute#firewallPolicyRule", + "match": { + "layer4Configs": [ + { + "ipProtocol": "tcp" + } + ], + "srcIpRanges": [ + "10.100.0.1/32" + ] + }, + "priority": 9000, + "ruleTupleCount": 2 +} + +--- + +POST https://compute.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/removeRule?priority=9000 +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: firewall_policy=774029050012 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "removeFirewallRuleFromFirewallPolicy", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/locations/global/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: operation=${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "removeFirewallRuleFromFirewallPolicy", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012?alt=json +Content-Type: application/json +User-Agent: kcc/controller-manager DeclarativeClientLib/0.0.1 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "description": "A basic folder firewall policy", + "displayName": "firewallpolicy-${uniqueId}", + "fingerprint": "abcdef0123A=", + "id": "000000000000000000000", + "kind": "compute#firewallPolicy", + "name": "774029050012", + "parent": "organizations/${organizationID}", + "ruleTupleCount": 8, + "rules": [ + { + "action": "goto_next", + "description": "default egress rule ipv6", + "direction": "EGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "destIpRanges": [ + "::/0" + ], + "layer4Configs": [ + { + "ipProtocol": "all" + } + ] + }, + "priority": 2147483644, + "ruleTupleCount": 2 + }, + { + "action": "goto_next", + "description": "default ingress rule ipv6", + "direction": "INGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "layer4Configs": [ + { + "ipProtocol": "all" + } + ], + "srcIpRanges": [ + "::/0" + ] + }, + "priority": 2147483645, + "ruleTupleCount": 2 + }, + { + "action": "goto_next", + "description": "default egress rule", + "direction": "EGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "destIpRanges": [ + "0.0.0.0/0" + ], + "layer4Configs": [ + { + "ipProtocol": "all" + } + ] + }, + "priority": 2147483646, + "ruleTupleCount": 2 + }, + { + "action": "goto_next", + "description": "default ingress rule", + "direction": "INGRESS", + "enableLogging": false, + "kind": "compute#firewallPolicyRule", + "match": { + "layer4Configs": [ + { + "ipProtocol": "all" + } + ], + "srcIpRanges": [ + "0.0.0.0/0" + ] + }, + "priority": 2147483647, + "ruleTupleCount": 2 + } + ], + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012/774029050012", + "shortName": "firewallpolicy-${uniqueId}" +} + +--- + +DELETE https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012?alt=json +Content-Type: application/json +User-Agent: kcc/controller-manager DeclarativeClientLib/0.0.1 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "deleteFirewallPolicy", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}?alt=json +Content-Type: application/json +User-Agent: kcc/controller-manager DeclarativeClientLib/0.0.1 + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "deleteFirewallPolicy", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "774029050012", + "targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012", + "user": "user@example.com" +} + +--- + +GET https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/774029050012?alt=json +Content-Type: application/json +User-Agent: kcc/controller-manager DeclarativeClientLib/0.0.1 + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'locations/global/firewallPolicies/774029050012' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'locations/global/firewallPolicies/774029050012' was not found" + } +} \ No newline at end of file