Skip to content

Commit

Permalink
add host-rewrite annotations (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
wasaga authored Oct 19, 2021
1 parent ee0500d commit 56c627a
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 53 deletions.
20 changes: 8 additions & 12 deletions controllers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ type PomeriumReconciler interface {
// Upsert should update or create the pomerium routes corresponding to this ingress
Upsert(ctx context.Context, ic *model.IngressConfig) (changes bool, err error)
// Set configuration to match provided ingresses
Set(ctx context.Context, ics []*model.IngressConfig) error
Set(ctx context.Context, ics []*model.IngressConfig) (changes bool, err error)
// Delete should delete pomerium routes corresponding to this ingress name
Delete(ctx context.Context, namespacedName types.NamespacedName) error
}

// reconcileInitial walks over all ingresses and updates configuration at once
// this is currently done for performance reasons
func (r *ingressController) reconcileInitial(ctx context.Context) error {
logger := log.FromContext(ctx).WithName("initial sync")
logger := log.FromContext(ctx).WithName("initial-sync")
logger.Info("starting...")
defer logger.Info("complete")

Expand All @@ -143,12 +143,12 @@ func (r *ingressController) reconcileInitial(ctx context.Context) error {
ics = append(ics, ic)
}

err := r.PomeriumReconciler.Set(ctx, ics)
changed, err := r.PomeriumReconciler.Set(ctx, ics)
for i := range ingressList.Items {
ingress := &ingressList.Items[i]
if err != nil {
r.EventRecorder.Event(ingress, corev1.EventTypeWarning, reasonPomeriumConfigUpdateError, err.Error())
} else {
} else if changed {
r.EventRecorder.Event(ingress, corev1.EventTypeNormal, reasonPomeriumConfigUpdated, msgPomeriumConfigUpdated)
}
}
Expand All @@ -164,25 +164,21 @@ func (r *ingressController) Reconcile(ctx context.Context, req ctrl.Request) (ct
}

logger := log.FromContext(ctx)
logger.Info("Reconcile")

ingress := new(networkingv1.Ingress)
if err := r.Client.Get(ctx, req.NamespacedName, ingress); err != nil {
if !apierrors.IsNotFound(err) {
return ctrl.Result{Requeue: true}, fmt.Errorf("get ingress: %w", err)
}
logger.Info("the ingress was deleted")
return r.deleteIngress(ctx, req.NamespacedName)
return r.deleteIngress(ctx, req.NamespacedName, "Ingress resource was deleted")
}

managing, err := r.isManaging(ctx, ingress)
if err != nil {
return ctrl.Result{Requeue: true}, fmt.Errorf("get ingressClass info: %w", err)
}

logger.Info("got ingress", "managing", managing, "version", ingress.GetResourceVersion())
if !managing {
return r.deleteIngress(ctx, req.NamespacedName)
return r.deleteIngress(ctx, req.NamespacedName, "not marked to be managed by this controller")
}

ic, err := r.fetchIngress(ctx, ingress)
Expand All @@ -195,11 +191,11 @@ func (r *ingressController) Reconcile(ctx context.Context, req ctrl.Request) (ct
return r.upsertIngress(ctx, ic)
}

func (r *ingressController) deleteIngress(ctx context.Context, name types.NamespacedName) (ctrl.Result, error) {
func (r *ingressController) deleteIngress(ctx context.Context, name types.NamespacedName, reason string) (ctrl.Result, error) {
if err := r.PomeriumReconciler.Delete(ctx, name); err != nil {
return ctrl.Result{Requeue: true}, fmt.Errorf("deleting ingress: %w", err)
}
log.FromContext(ctx).Info("ingress deleted")
log.FromContext(ctx).Info("deleted from pomerium", "reason", reason)
r.Registry.DeleteCascade(model.Key{Kind: r.ingressKind, NamespacedName: name})
return ctrl.Result{}, nil
}
Expand Down
6 changes: 3 additions & 3 deletions controllers/controller_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ func (m *mockPomeriumReconciler) Delete(ctx context.Context, name types.Namespac
return nil
}

func (m *mockPomeriumReconciler) Set(ctx context.Context, ics []*model.IngressConfig) error {
func (m *mockPomeriumReconciler) Set(ctx context.Context, ics []*model.IngressConfig) (bool, error) {
if len(ics) != 0 {
return errors.New("unexpected ingresses")
return false, errors.New("unexpected ingresses")
}
return nil
return false, nil
}

func (s *ControllerTestSuite) EventuallyDeleted(name types.NamespacedName) {
Expand Down
4 changes: 4 additions & 0 deletions pomerium/ingress_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ var (
"set_response_headers",
"rewrite_response_headers",
"preserve_host_header",
"host_rewrite",
"host_rewrite_header",
"host_path_regex_rewrite_pattern",
"host_path_regex_rewrite_substitution",
"pass_identity_headers",
"tls_skip_verify",
"tls_server_name",
Expand Down
61 changes: 35 additions & 26 deletions pomerium/ingress_annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,42 @@ var (
)

func TestAnnotations(t *testing.T) {
strp := func(txt string) *string { return &txt }
r := &pb.Route{To: []string{"http://upstream.svc.cluster.local"}}
ic := &model.IngressConfig{
AnnotationPrefix: "a",
Ingress: &networkingv1.Ingress{
ObjectMeta: v1.ObjectMeta{
Namespace: "test",
Annotations: map[string]string{
"a/allowed_users": `["a"]`,
"a/allowed_groups": `["a"]`,
"a/allowed_domains": `["a"]`,
"a/allowed_idp_claims": `{"key": ["val1", "val2"]}`,
"a/policy": testPPL,
"a/cors_allow_preflight": "true",
"a/allow_public_unauthenticated_access": "false",
"a/allow_any_authenticated_user": "false",
"a/timeout": `10s`,
"a/idle_timeout": `60s`,
"a/allow_websockets": "true",
"a/set_request_headers": `{"a": "aaa"}`,
"a/remove_request_headers": `["a"]`,
"a/set_response_headers": `{"c": "ccc"}`,
"a/rewrite_response_headers": `[{"header": "a", "prefix": "b", "value": "c"}]`,
"a/preserve_host_header": "true",
"a/pass_identity_headers": "true",
"a/health_checks": `[{"timeout": "10s", "interval": "60s", "healthy_threshold": 1, "unhealthy_threshold": 2, "http_health_check": {"path": "/"}}]`,
"a/tls_skip_verify": "true",
"a/tls_server_name": "my.server.name",
"a/tls_custom_ca_secret": "my_custom_ca_secret",
"a/tls_client_secret": "my_client_secret",
"a/tls_downstream_client_ca_secret": "my_downstream_client_ca_secret",
"a/secure_upstream": "true",
"a/allowed_users": `["a"]`,
"a/allowed_groups": `["a"]`,
"a/allowed_domains": `["a"]`,
"a/allowed_idp_claims": `{"key": ["val1", "val2"]}`,
"a/policy": testPPL,
"a/cors_allow_preflight": "true",
"a/allow_public_unauthenticated_access": "false",
"a/allow_any_authenticated_user": "false",
"a/timeout": `10s`,
"a/idle_timeout": `60s`,
"a/allow_websockets": "true",
"a/set_request_headers": `{"a": "aaa"}`,
"a/remove_request_headers": `["a"]`,
"a/set_response_headers": `{"c": "ccc"}`,
"a/rewrite_response_headers": `[{"header": "a", "prefix": "b", "value": "c"}]`,
"a/preserve_host_header": "true",
"a/host_rewrite": "rewrite",
"a/host_rewrite_header": "rewrite-header",
"a/host_path_regex_rewrite_pattern": "rewrite-pattern",
"a/host_path_regex_rewrite_substitution": "rewrite-sub",
"a/pass_identity_headers": "true",
"a/health_checks": `[{"timeout": "10s", "interval": "60s", "healthy_threshold": 1, "unhealthy_threshold": 2, "http_health_check": {"path": "/"}}]`,
"a/tls_skip_verify": "true",
"a/tls_server_name": "my.server.name",
"a/tls_custom_ca_secret": "my_custom_ca_secret",
"a/tls_client_secret": "my_client_secret",
"a/tls_downstream_client_ca_secret": "my_downstream_client_ca_secret",
"a/secure_upstream": "true",
},
},
},
Expand Down Expand Up @@ -103,8 +108,12 @@ func TestAnnotations(t *testing.T) {
Matcher: &pb.RouteRewriteHeader_Prefix{Prefix: "b"},
Value: "c",
}},
PreserveHostHeader: true,
PassIdentityHeaders: true,
PreserveHostHeader: true,
HostRewrite: strp("rewrite"),
HostRewriteHeader: strp("rewrite-header"),
HostPathRegexRewritePattern: strp("rewrite-pattern"),
HostPathRegexRewriteSubstitution: strp("rewrite-sub"),
PassIdentityHeaders: true,
EnvoyOpts: &envoy_config_cluster_v3.Cluster{
HealthChecks: []*envoy_config_core_v3.HealthCheck{{
Timeout: durationpb.New(time.Second * 10),
Expand Down
20 changes: 8 additions & 12 deletions pomerium/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ func (r *ConfigReconciler) Upsert(ctx context.Context, ic *model.IngressConfig)
return r.saveConfig(ctx, prev, next, string(ic.Ingress.UID))
}

func (r *ConfigReconciler) Set(ctx context.Context, ics []*model.IngressConfig) error {
func (r *ConfigReconciler) Set(ctx context.Context, ics []*model.IngressConfig) (bool, error) {
logger := log.FromContext(ctx)

prev, err := r.getConfig(ctx)
if err != nil {
return fmt.Errorf("get config: %w", err)
return false, fmt.Errorf("get config: %w", err)
}
next := new(pb.Config)

Expand All @@ -73,11 +73,7 @@ func (r *ConfigReconciler) Set(ctx context.Context, ics []*model.IngressConfig)
next = cfg
}

if _, err := r.saveConfig(ctx, prev, next, "config"); err != nil {
return fmt.Errorf("saving config: %w", err)
}

return nil
return r.saveConfig(ctx, prev, next, "config")
}

// Delete should delete pomerium routes corresponding to this ingress name
Expand Down Expand Up @@ -145,12 +141,16 @@ func (r *ConfigReconciler) saveConfig(ctx context.Context, prev, next *pb.Config
// envoy matches according to the order routes are present in the configuration
sort.Sort(routeList(next.Routes))

if r.DebugDumpConfigDiff {
debugDumpConfigDiff(prev, next)
}

if err := validate(ctx, next, id); err != nil {
return false, fmt.Errorf("config validation: %w", err)
}

if proto.Equal(prev, next) {
logger.Info("no changes detected")
logger.V(1).Info("no changes in the config")
return false, nil
}

Expand All @@ -167,10 +167,6 @@ func (r *ConfigReconciler) saveConfig(ctx context.Context, prev, next *pb.Config

logger.Info("new pomerium config applied")

if r.DebugDumpConfigDiff {
debugDumpConfigDiff(prev, next)
}

return true, nil
}

Expand Down

0 comments on commit 56c627a

Please sign in to comment.