Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for initial_metadata to AuthService #3639

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Please see the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest

We're pleased to introduce Emissary 2.0.1 as a developer preview. The 2.X family introduces a number of changes to allow Emissary to more gracefully handle larger installations, reduce global configuration to better handle multitenant or multiorganizational installations, reduce memory footprint, and improve performance. We welcome feedback!! Join us on <a href="https://a8r.io/slack">Slack</a> and let us know what you think.

- Feature: Support passing metadata to external authentication services.
- Feature: The optional `statsPrefix` element of the `AmbassadorListener` CRD now determines the prefix of HTTP statistics emitted for a specific `AmbassadorListener`.
- Feature: Ambassador Agent reports sidecar process information and Mapping OpenAPI documentation to Ambassador Cloud to provide more visibility into services and clusters.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ spec:
- allow_partial
- max_bytes
type: object
initial_metadata:
additionalProperties:
type: string
type: object
path_prefix:
type: string
proto:
Expand Down
5 changes: 5 additions & 0 deletions cmd/kat-server/services/grpc-auth-v3.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"google.golang.org/genproto/googleapis/rpc/code"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)

// GRPCAUTHV3 server object (all fields are required).
Expand Down Expand Up @@ -164,6 +165,10 @@ func (g *GRPCAUTHV3) Check(ctx context.Context, r *pb.CheckRequest) (*pb.CheckRe
if rs.GetHTTPHeaderMap() != nil {
results["headers"] = *rs.GetHTTPHeaderMap()
}
md, ok := metadata.FromIncomingContext(ctx)
if ok {
results["metadata"] = md
}
body, err := json.MarshalIndent(results, "", " ")
if err != nil {
body = []byte(fmt.Sprintf("Error: %v", err))
Expand Down
5 changes: 5 additions & 0 deletions cmd/kat-server/services/grpc-auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"google.golang.org/genproto/googleapis/rpc/code"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"

// first party (protobuf)
core "github.com/datawire/ambassador/v2/pkg/api/envoy/api/v2/core"
Expand Down Expand Up @@ -164,6 +165,10 @@ func (g *GRPCAUTH) Check(ctx context.Context, r *pb.CheckRequest) (*pb.CheckResp
if rs.GetHTTPHeaderMap() != nil {
results["headers"] = *rs.GetHTTPHeaderMap()
}
md, ok := metadata.FromIncomingContext(ctx)
if ok {
results["metadata"] = md
}
body, err := json.MarshalIndent(results, "", " ")
if err != nil {
body = []byte(fmt.Sprintf("Error: %v", err))
Expand Down
4 changes: 4 additions & 0 deletions manifests/emissary/ambassador-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ spec:
- allow_partial
- max_bytes
type: object
initial_metadata:
additionalProperties:
type: string
type: object
path_prefix:
type: string
proto:
Expand Down
4 changes: 4 additions & 0 deletions manifests/emissary/emissary-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ spec:
- allow_partial
- max_bytes
type: object
initial_metadata:
additionalProperties:
type: string
type: object
path_prefix:
type: string
proto:
Expand Down
1 change: 1 addition & 0 deletions pkg/api/getambassador.io/v2/authservice_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type AuthServiceSpec struct {
AllowedRequestHeaders []string `json:"allowed_request_headers,omitempty"`
AllowedAuthorizationHeaders []string `json:"allowed_authorization_headers,omitempty"`
AddAuthHeaders map[string]BoolOrString `json:"add_auth_headers,omitempty"`
InitialMetadata map[string]string `json:"initial_metadata,omitempty"`
AllowRequestBody *bool `json:"allow_request_body,omitempty"`
AddLinkerdHeaders *bool `json:"add_linkerd_headers,omitempty"`
FailureModeAllow *bool `json:"failure_mode_allow,omitempty"`
Expand Down
7 changes: 7 additions & 0 deletions pkg/api/getambassador.io/v2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion python/ambassador/envoy/v2/v2httpfilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,15 @@ def V2HTTPFilter_authv1(auth: IRAuth, v2config: 'V2Config'):
}

if auth.proto == "grpc":
initial_metadata = []
protocol_version = auth.get('protocol_version', 'v2')

for k, v in auth.get('initial_metadata', {}).items():
initial_metadata.append({
'key': k,
'value': v,
})

auth_info = {
'name': 'envoy.filters.http.ext_authz',
'typed_config': {
Expand All @@ -328,7 +336,8 @@ def V2HTTPFilter_authv1(auth: IRAuth, v2config: 'V2Config'):
'envoy_grpc': {
'cluster_name': cluster.envoy_name
},
'timeout': "%0.3fs" % (float(auth.timeout_ms) / 1000.0)
'timeout': "%0.3fs" % (float(auth.timeout_ms) / 1000.0),
'initial_metadata': initial_metadata
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion python/ambassador/envoy/v3/v3httpfilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,15 @@ def V3HTTPFilter_authv1(auth: IRAuth, v3config: 'V3Config'):
}

if auth.proto == "grpc":
initial_metadata = []
protocol_version = auth.get('protocol_version', 'v2')

for k, v in auth.get('initial_metadata', {}).items():
initial_metadata.append({
'key': k,
'value': v,
})

auth_info = {
'name': 'envoy.filters.http.ext_authz',
'typed_config': {
Expand All @@ -334,7 +342,8 @@ def V3HTTPFilter_authv1(auth: IRAuth, v3config: 'V3Config'):
'envoy_grpc': {
'cluster_name': cluster.envoy_name
},
'timeout': "%0.3fs" % (float(auth.timeout_ms) / 1000.0)
'timeout': "%0.3fs" % (float(auth.timeout_ms) / 1000.0),
'initial_metadata': initial_metadata
},
'transport_api_version': protocol_version.replace("alpha", "").upper(),
}
Expand Down
1 change: 1 addition & 0 deletions python/ambassador/ir/irauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def _load_auth(self, module: Resource, ir: 'IR'):
self["connect_timeout_ms"] = module.get("connect_timeout_ms", 3000)
self["cluster_idle_timeout_ms"] = module.get("cluster_idle_timeout_ms", None)
self["cluster_max_connection_lifetime_ms"] = module.get("cluster_max_connection_lifetime_ms", None)
self["initial_metadata"] = module.get("initial_metadata", {})
self["add_auth_headers"] = module.get("add_auth_headers", {})
self["protocol_version"] = module.get("protocol_version", "v2")
self.__to_header_list('allowed_headers', module)
Expand Down
4 changes: 4 additions & 0 deletions python/kat/harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,7 @@ def __init__(self, bres):

if isinstance(bres, dict):
self.name = bres.get("backend")
self.metadata = bres.get("metadata")
self.request = BackendRequest(bres["request"]) if "request" in bres else None
self.response = BackendResponse(bres["response"]) if "response" in bres else None

Expand All @@ -1016,6 +1017,9 @@ def as_dict(self) -> Dict[str, Any]:
'name': self.name
}

if self.metadata:
od['metadata'] = self.metadata

if self.request:
od['request'] = dictify(self.request)

Expand Down
4 changes: 4 additions & 0 deletions python/schemas/v2/AuthService.schema
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
"type": "object",
"additionalProperties": { "type": [ "string", "boolean" ] }
},
"initial_metadata": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"allow_request_body": { "type": "boolean" },
"add_linkerd_headers": { "type": "boolean" },
"include_body": {
Expand Down
6 changes: 6 additions & 0 deletions python/tests/kat/t_extauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ def config(self):
auth_service: "{self.auth.path.fqdn}"
timeout_ms: 5000
proto: grpc
initial_metadata:
X-Init-Meta: init-meta
""")
yield self, self.format("""
---
Expand Down Expand Up @@ -104,6 +106,7 @@ def check(self):
assert self.results[0].backend.request.headers["x-forwarded-proto"]== ["http"]
assert "user-agent" in self.results[0].backend.request.headers
assert "baz" in self.results[0].backend.request.headers
assert self.results[0].backend.metadata["x-init-meta"]== ["init-meta"]
assert self.results[0].status == 401
assert self.results[0].headers["Server"] == ["envoy"]
assert self.results[0].headers['X-Grpc-Service-Protocol-Version'] == ['v2']
Expand Down Expand Up @@ -978,6 +981,8 @@ def config(self):
timeout_ms: 5000
protocol_version: "v3"
proto: grpc
initial_metadata:
X-Init-Meta: init-meta
""")
yield self, self.format("""
---
Expand Down Expand Up @@ -1021,6 +1026,7 @@ def check(self):
assert self.results[0].status == 401
assert self.results[0].headers["Server"] == ["envoy"]
assert self.results[0].headers['X-Grpc-Service-Protocol-Version'] == ['v3']
assert self.results[0].backend.metadata["x-init-meta"]== ["init-meta"]

# [1] Verifies that Location header is returned from Envoy.
assert self.results[1].backend.name == self.auth.path.k8s
Expand Down