未验证 提交 cc4fb467 编写于 作者: A Alessandro (Ale) Segala 提交者: GitHub

Add `envRef` in addition to `secretKeyRef` in metadata for Components and HTTPEndpoints (#6496)

* WIP: Updated CRDs
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Reduce code duplication in CRDs
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* WIP
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Fixes
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Added envRef to Dapr components and HTTP endpoints
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Add E2E tests
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Renamed shared->common
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Add allowlist for K8s mode
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* CRDs: Ensure `value` is parsed as string
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Should now fix the CRDs for good
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

* Fixed issues after merge
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>

---------
Signed-off-by: NItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
Co-authored-by: NDapr Bot <56698301+dapr-bot@users.noreply.github.com>
上级 e7641ff6
/dist
.idea
**/.DS_Store
config/crd/bases
github.com/
......
......@@ -12,7 +12,7 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: Component describes an Dapr component type
description: Component describes an Dapr component type.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
......@@ -20,7 +20,7 @@ spec:
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
auth:
description: Auth represents authentication details for the component
description: Auth represents authentication details for the component.
properties:
secretStore:
type: string
......@@ -39,32 +39,38 @@ spec:
type: string
type: array
spec:
description: ComponentSpec is the spec for a component
description: ComponentSpec is the spec for a component.
properties:
initTimeout:
type: string
ignoreErrors:
type: boolean
initTimeout:
type: string
metadata:
items:
description: MetadataItem is a name/value pair for a metadata
description: NameValuePair is a name/value pair.
properties:
envRef:
description: EnvRef is the name of an environmental variable
to read the value from.
type: string
name:
description: Name of the property.
type: string
secretKeyRef:
description: SecretKeyRef is a reference to a secret holding
the value for the metadata item. Name is the secret name,
and key is the field in the secret.
description: SecretKeyRef is the reference of a value in a secret
store component.
properties:
key:
description: Field in the secret.
type: string
name:
description: Secret name.
type: string
required:
- key
- name
type: object
value:
description: Value of the property, in plaintext.
x-kubernetes-preserve-unknown-fields: true
required:
- name
......
......@@ -18,10 +18,14 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: HTTPEndpoint describes a Dapr HTTPEndpoint type for external service invocation. This endpoint can be external to Dapr, or external to the environment.
description: HTTPEndpoint describes a Dapr HTTPEndpoint type for external
service invocation. This endpoint can be external to Dapr, or external to
the environment.
properties:
apiVersion:
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'
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
auth:
description: Auth represents authentication details for the component.
......@@ -32,7 +36,9 @@ spec:
- secretStore
type: object
kind:
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'
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
metadata:
type: object
......@@ -41,28 +47,37 @@ spec:
type: string
type: array
spec:
description: HTTPEndpointSpec describes an access specification for allowing external service invocations.
description: HTTPEndpointSpec describes an access specification for allowing
external service invocations.
properties:
baseUrl:
type: string
headers:
items:
description: Header is the name/value pair for a header specification.
description: NameValuePair is a name/value pair.
properties:
envRef:
description: EnvRef is the name of an environmental variable
to read the value from.
type: string
name:
description: Name of the property.
type: string
secretKeyRef:
description: SecretKeyRef is a reference to a secret holding the value for the metadata item. Name is the secret name, and key is the field in the secret.
description: SecretKeyRef is the reference of a value in a secret
store component.
properties:
key:
description: Field in the secret.
type: string
name:
description: Secret name.
type: string
required:
- key
- name
type: object
value:
description: Value of the property, in plaintext.
x-kubernetes-preserve-unknown-fields: true
required:
- name
......
/*
Copyright 2023 The Dapr Authors
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 common
// +kubebuilder:object:generate=true
import (
"strconv"
apiextensionsV1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
// NameValuePair is a name/value pair.
type NameValuePair struct {
// Name of the property.
Name string `json:"name"`
// Value of the property, in plaintext.
//+optional
Value DynamicValue `json:"value,omitempty"`
// SecretKeyRef is the reference of a value in a secret store component.
//+optional
SecretKeyRef SecretKeyRef `json:"secretKeyRef,omitempty"`
// EnvRef is the name of an environmental variable to read the value from.
//+optional
EnvRef string `json:"envRef,omitempty"`
}
// HasValue returns true if the NameValuePair has a non-empty value.
func (nvp NameValuePair) HasValue() bool {
return len(nvp.Value.JSON.Raw) > 0
}
// SetValue sets the value.
func (nvp *NameValuePair) SetValue(val []byte) {
nvp.Value = DynamicValue{
JSON: apiextensionsV1.JSON{
Raw: val,
},
}
}
// SecretKeyRef is a reference to a secret holding the value for the name/value item.
type SecretKeyRef struct {
// Secret name.
Name string `json:"name"`
// Field in the secret.
//+optional
Key string `json:"key"`
}
// DynamicValue is a dynamic value struct for the component.metadata pair value.
// +kubebuilder:validation:Type=""
// +kubebuilder:validation:Schemaless
type DynamicValue struct {
apiextensionsV1.JSON `json:",inline"`
}
// String returns the string representation of the raw value.
// If the value is a string, it will be unquoted as the string is guaranteed to be a JSON serialized string.
func (d *DynamicValue) String() string {
s := string(d.Raw)
c, err := strconv.Unquote(s)
if err == nil {
s = c
}
return s
}
/*
Copyright 2023 The Dapr Authors
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 common
// +kubebuilder:object:generate=true
// Scoped is a base struct for components and other resources that can be scoped to apps.
type Scoped struct {
//+optional
Scopes []string `json:"scopes,omitempty"`
}
// IsAppScoped returns true if the appID is allowed in the scopes for the resource.
func (s Scoped) IsAppScoped(appID string) bool {
if len(s.Scopes) == 0 {
// If there are no scopes, then every app is allowed
return true
}
for _, s := range s.Scopes {
if s == appID {
return true
}
}
return false
}
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Dapr Authors.
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 controller-gen. DO NOT EDIT.
package common
import ()
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DynamicValue) DeepCopyInto(out *DynamicValue) {
*out = *in
in.JSON.DeepCopyInto(&out.JSON)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicValue.
func (in *DynamicValue) DeepCopy() *DynamicValue {
if in == nil {
return nil
}
out := new(DynamicValue)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NameValuePair) DeepCopyInto(out *NameValuePair) {
*out = *in
in.Value.DeepCopyInto(&out.Value)
out.SecretKeyRef = in.SecretKeyRef
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameValuePair.
func (in *NameValuePair) DeepCopy() *NameValuePair {
if in == nil {
return nil
}
out := new(NameValuePair)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Scoped) DeepCopyInto(out *Scoped) {
*out = *in
if in.Scopes != nil {
in, out := &in.Scopes, &out.Scopes
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scoped.
func (in *Scoped) DeepCopy() *Scoped {
if in == nil {
return nil
}
out := new(Scoped)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretKeyRef) DeepCopyInto(out *SecretKeyRef) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeyRef.
func (in *SecretKeyRef) DeepCopy() *SecretKeyRef {
if in == nil {
return nil
}
out := new(SecretKeyRef)
in.DeepCopyInto(out)
return out
}
......@@ -14,11 +14,9 @@ limitations under the License.
package v1alpha1
import (
"strconv"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/dapr/dapr/pkg/apis/common"
"github.com/dapr/dapr/utils"
)
......@@ -34,9 +32,8 @@ type Component struct {
//+optional
Spec ComponentSpec `json:"spec,omitempty"`
//+optional
Auth `json:"auth,omitempty"`
//+optional
Scopes []string `json:"scopes,omitempty"`
Auth `json:"auth,omitempty"`
common.Scoped `json:",inline"`
}
// Kind returns the component kind.
......@@ -49,20 +46,14 @@ func (c Component) LogName() string {
return utils.ComponentLogName(c.ObjectMeta.Name, c.Spec.Type, c.Spec.Version)
}
// IsAppScoped returns true if the appID is allowed in the scopes for the component.
func (c Component) IsAppScoped(appID string) bool {
if len(c.Scopes) == 0 {
// If there are no scopes, then every app is allowed
return true
}
for _, s := range c.Scopes {
if s == appID {
return true
}
}
// GetSecretStore returns the name of the secret store.
func (c Component) GetSecretStore() string {
return c.Auth.SecretStore
}
return false
// NameValuePairs returns the component's metadata as name/value pairs
func (c Component) NameValuePairs() []common.NameValuePair {
return c.Spec.Metadata
}
// ComponentSpec is the spec for a component.
......@@ -70,27 +61,12 @@ type ComponentSpec struct {
Type string `json:"type"`
Version string `json:"version"`
//+optional
IgnoreErrors bool `json:"ignoreErrors"`
Metadata []MetadataItem `json:"metadata"`
IgnoreErrors bool `json:"ignoreErrors"`
Metadata []common.NameValuePair `json:"metadata"`
//+optional
InitTimeout string `json:"initTimeout"`
}
// MetadataItem is a name/value pair for a metadata.
type MetadataItem struct {
Name string `json:"name"`
//+optional
Value DynamicValue `json:"value,omitempty"`
//+optional
SecretKeyRef SecretKeyRef `json:"secretKeyRef,omitempty"`
}
// SecretKeyRef is a reference to a secret holding the value for the metadata item. Name is the secret name, and key is the field in the secret.
type SecretKeyRef struct {
Name string `json:"name"`
Key string `json:"key"`
}
// Auth represents authentication details for the component.
type Auth struct {
SecretStore string `json:"secretStore"`
......@@ -105,19 +81,3 @@ type ComponentList struct {
Items []Component `json:"items"`
}
// DynamicValue is a dynamic value struct for the component.metadata pair value.
type DynamicValue struct {
v1.JSON `json:",inline"`
}
// String returns the string representation of the raw value.
// If the value is a string, it will be unquoted as the string is guaranteed to be a JSON serialized string.
func (d *DynamicValue) String() string {
s := string(d.Raw)
c, err := strconv.Unquote(s)
if err == nil {
s = c
}
return s
}
......@@ -22,6 +22,7 @@ limitations under the License.
package v1alpha1
import (
"github.com/dapr/dapr/pkg/apis/common"
"k8s.io/apimachinery/pkg/runtime"
)
......@@ -47,11 +48,7 @@ func (in *Component) DeepCopyInto(out *Component) {
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Auth = in.Auth
if in.Scopes != nil {
in, out := &in.Scopes, &out.Scopes
*out = make([]string, len(*in))
copy(*out, *in)
}
in.Scoped.DeepCopyInto(&out.Scoped)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Component.
......@@ -109,7 +106,7 @@ func (in *ComponentSpec) DeepCopyInto(out *ComponentSpec) {
*out = *in
if in.Metadata != nil {
in, out := &in.Metadata, &out.Metadata
*out = make([]MetadataItem, len(*in))
*out = make([]common.NameValuePair, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
......@@ -125,51 +122,3 @@ func (in *ComponentSpec) DeepCopy() *ComponentSpec {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DynamicValue) DeepCopyInto(out *DynamicValue) {
*out = *in
in.JSON.DeepCopyInto(&out.JSON)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicValue.
func (in *DynamicValue) DeepCopy() *DynamicValue {
if in == nil {
return nil
}
out := new(DynamicValue)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MetadataItem) DeepCopyInto(out *MetadataItem) {
*out = *in
in.Value.DeepCopyInto(&out.Value)
out.SecretKeyRef = in.SecretKeyRef
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetadataItem.
func (in *MetadataItem) DeepCopy() *MetadataItem {
if in == nil {
return nil
}
out := new(MetadataItem)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretKeyRef) DeepCopyInto(out *SecretKeyRef) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeyRef.
func (in *SecretKeyRef) DeepCopy() *SecretKeyRef {
if in == nil {
return nil
}
out := new(SecretKeyRef)
in.DeepCopyInto(out)
return out
}
......@@ -14,10 +14,9 @@ limitations under the License.
package v1alpha1
import (
"strconv"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/dapr/dapr/pkg/apis/common"
)
//+genclient
......@@ -33,9 +32,8 @@ type HTTPEndpoint struct {
//+optional
Spec HTTPEndpointSpec `json:"spec,omitempty"`
//+optional
Auth `json:"auth,omitempty"`
//+optional
Scopes []string `json:"scopes,omitempty"`
Auth `json:"auth,omitempty"`
common.Scoped `json:",inline"`
}
// Kind returns the component kind.
......@@ -43,42 +41,21 @@ func (HTTPEndpoint) Kind() string {
return "HTTPEndpoint"
}
// IsAppScoped returns true if the appID is allowed in the scopes for the http endpoint.
func (e HTTPEndpoint) IsAppScoped(appID string) bool {
if len(e.Scopes) == 0 {
// If there are no scopes, then every app is allowed
return true
}
for _, s := range e.Scopes {
if s == appID {
return true
}
}
return false
// GetSecretStore returns the name of the secret store.
func (h HTTPEndpoint) GetSecretStore() string {
return h.Auth.SecretStore
}
// Header is the name/value pair for a header specification.
type Header struct {
Name string `json:"name"`
//+optional
Value DynamicValue `json:"value"`
//+optional
SecretKeyRef SecretKeyRef `json:"secretKeyRef,omitempty"`
// NameValuePairs returns the component's headers as name/value pairs
func (h HTTPEndpoint) NameValuePairs() []common.NameValuePair {
return h.Spec.Headers
}
// HTTPEndpointSpec describes an access specification for allowing external service invocations.
type HTTPEndpointSpec struct {
BaseURL string `json:"baseUrl" validate:"required"`
//+optional
Headers []Header `json:"headers"`
}
// SecretKeyRef is a reference to a secret holding the value for the metadata item. Name is the secret name, and key is the field in the secret.
type SecretKeyRef struct {
Name string `json:"name" validate:"required"`
Key string `json:"key" validate:"required"`
Headers []common.NameValuePair `json:"headers"`
}
// Auth represents authentication details for the component.
......@@ -95,20 +72,3 @@ type HTTPEndpointList struct {
Items []HTTPEndpoint `json:"items"`
}
// DynamicValue is a dynamic value struct for the header.value.
type DynamicValue struct {
v1.JSON `json:",inline"`
}
// String returns the string representation of the raw value.
// If the value is a string, it will be unquoted as the string is guaranteed to be a JSON serialized string.
func (d *DynamicValue) String() string {
s := string(d.Raw)
c, err := strconv.Unquote(s)
if err == nil {
s = c
}
return s
}
......@@ -22,6 +22,7 @@ limitations under the License.
package v1alpha1
import (
"github.com/dapr/dapr/pkg/apis/common"
"k8s.io/apimachinery/pkg/runtime"
)
......@@ -40,22 +41,6 @@ func (in *Auth) DeepCopy() *Auth {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DynamicValue) DeepCopyInto(out *DynamicValue) {
*out = *in
in.JSON.DeepCopyInto(&out.JSON)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicValue.
func (in *DynamicValue) DeepCopy() *DynamicValue {
if in == nil {
return nil
}
out := new(DynamicValue)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HTTPEndpoint) DeepCopyInto(out *HTTPEndpoint) {
*out = *in
......@@ -63,11 +48,7 @@ func (in *HTTPEndpoint) DeepCopyInto(out *HTTPEndpoint) {
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Auth = in.Auth
if in.Scopes != nil {
in, out := &in.Scopes, &out.Scopes
*out = make([]string, len(*in))
copy(*out, *in)
}
in.Scoped.DeepCopyInto(&out.Scoped)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPEndpoint.
......@@ -125,7 +106,7 @@ func (in *HTTPEndpointSpec) DeepCopyInto(out *HTTPEndpointSpec) {
*out = *in
if in.Headers != nil {
in, out := &in.Headers, &out.Headers
*out = make([]Header, len(*in))
*out = make([]common.NameValuePair, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
......@@ -141,35 +122,3 @@ func (in *HTTPEndpointSpec) DeepCopy() *HTTPEndpointSpec {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Header) DeepCopyInto(out *Header) {
*out = *in
in.Value.DeepCopyInto(&out.Value)
out.SecretKeyRef = in.SecretKeyRef
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Header.
func (in *Header) DeepCopy() *Header {
if in == nil {
return nil
}
out := new(Header)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretKeyRef) DeepCopyInto(out *SecretKeyRef) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeyRef.
func (in *SecretKeyRef) DeepCopy() *SecretKeyRef {
if in == nil {
return nil
}
out := new(SecretKeyRef)
in.DeepCopyInto(out)
return out
}
......@@ -27,7 +27,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
endpointV1alpha1 "github.com/dapr/dapr/pkg/apis/httpEndpoint/v1alpha1"
commonapi "github.com/dapr/dapr/pkg/apis/common"
"github.com/dapr/dapr/pkg/apphealth"
"github.com/dapr/dapr/pkg/channel"
"github.com/dapr/dapr/pkg/config"
......@@ -283,7 +283,7 @@ func (h *Channel) constructRequest(ctx context.Context, req *invokev1.InvokeMeth
msg := req.Message()
verb := msg.HttpExtension.Verb.String()
method := msg.Method
var headers []endpointV1alpha1.Header
var headers []commonapi.NameValuePair
uri := strings.Builder{}
......
......@@ -25,6 +25,7 @@ import (
"io"
"github.com/dapr/components-contrib/secretstores"
commonapi "github.com/dapr/dapr/pkg/apis/common"
"github.com/dapr/dapr/pkg/apis/components/v1alpha1"
)
......@@ -123,7 +124,7 @@ func ComponentEncryptionKey(component v1alpha1.Component, secretStore secretstor
return cek, nil
}
func tryGetEncryptionKeyFromMetadataItem(namespace string, item v1alpha1.MetadataItem, secretStore secretstores.SecretStore) (Key, error) {
func tryGetEncryptionKeyFromMetadataItem(namespace string, item commonapi.NameValuePair, secretStore secretstores.SecretStore) (Key, error) {
if item.SecretKeyRef.Name == "" {
return Key{}, fmt.Errorf("%s: secretKeyRef cannot be empty", errPrefix)
}
......
......@@ -21,6 +21,7 @@ import (
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/secretstores"
commonapi "github.com/dapr/dapr/pkg/apis/common"
"github.com/dapr/dapr/pkg/apis/components/v1alpha1"
"github.com/stretchr/testify/assert"
......@@ -65,16 +66,16 @@ func TestComponentEncryptionKey(t *testing.T) {
Name: "statestore",
},
Spec: v1alpha1.ComponentSpec{
Metadata: []v1alpha1.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: primaryEncryptionKey,
SecretKeyRef: v1alpha1.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "primaryKey",
},
},
{
Name: secondaryEncryptionKey,
SecretKeyRef: v1alpha1.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "secondaryKey",
},
},
......@@ -111,16 +112,16 @@ func TestComponentEncryptionKey(t *testing.T) {
Name: "statestore",
},
Spec: v1alpha1.ComponentSpec{
Metadata: []v1alpha1.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: primaryEncryptionKey,
SecretKeyRef: v1alpha1.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "primaryKey",
},
},
{
Name: secondaryEncryptionKey,
SecretKeyRef: v1alpha1.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "secondaryKey",
},
},
......@@ -140,7 +141,7 @@ func TestComponentEncryptionKey(t *testing.T) {
Name: "statestore",
},
Spec: v1alpha1.ComponentSpec{
Metadata: []v1alpha1.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "something",
},
......@@ -163,7 +164,7 @@ func TestTryGetEncryptionKeyFromMetadataItem(t *testing.T) {
},
}})
_, err := tryGetEncryptionKeyFromMetadataItem("", v1alpha1.MetadataItem{}, secretStore)
_, err := tryGetEncryptionKeyFromMetadataItem("", commonapi.NameValuePair{}, secretStore)
assert.Error(t, err)
})
}
......
......@@ -51,6 +51,7 @@ import (
"github.com/dapr/components-contrib/secretstores"
"github.com/dapr/components-contrib/state"
"github.com/dapr/dapr/pkg/actors"
commonapi "github.com/dapr/dapr/pkg/apis/common"
componentsV1alpha1 "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
httpEndpointsV1alpha1 "github.com/dapr/dapr/pkg/apis/httpEndpoint/v1alpha1"
"github.com/dapr/dapr/pkg/apis/resiliency/v1alpha1"
......@@ -4215,10 +4216,10 @@ func TestMetadata(t *testing.T) {
Spec: componentsV1alpha1.ComponentSpec{
Type: "mock.component1Type",
Version: "v1.0",
Metadata: []componentsV1alpha1.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "actorMockComponent1",
Value: componentsV1alpha1.DynamicValue{
Value: commonapi.DynamicValue{
JSON: v1.JSON{Raw: []byte("true")},
},
},
......@@ -4232,10 +4233,10 @@ func TestMetadata(t *testing.T) {
Spec: componentsV1alpha1.ComponentSpec{
Type: "mock.component2Type",
Version: "v1.0",
Metadata: []componentsV1alpha1.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "actorMockComponent2",
Value: componentsV1alpha1.DynamicValue{
Value: commonapi.DynamicValue{
JSON: v1.JSON{Raw: []byte("true")},
},
},
......@@ -4262,10 +4263,10 @@ func TestMetadata(t *testing.T) {
},
Spec: httpEndpointsV1alpha1.HTTPEndpointSpec{
BaseURL: "api.test.com",
Headers: []httpEndpointsV1alpha1.Header{
Headers: []commonapi.NameValuePair{
{
Name: "Accept-Language",
Value: httpEndpointsV1alpha1.DynamicValue{
Value: commonapi.DynamicValue{
JSON: v1.JSON{Raw: []byte("en-US")},
},
},
......
......@@ -39,7 +39,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/anypb"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsV1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/dapr/components-contrib/bindings"
......@@ -52,6 +52,7 @@ import (
workflowContrib "github.com/dapr/components-contrib/workflows"
"github.com/dapr/dapr/pkg/actors"
"github.com/dapr/dapr/pkg/actors/reminders"
commonapi "github.com/dapr/dapr/pkg/apis/common"
componentsV1alpha1 "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
httpEndpointsV1alpha1 "github.com/dapr/dapr/pkg/apis/httpEndpoint/v1alpha1"
"github.com/dapr/dapr/pkg/apis/resiliency/v1alpha1"
......@@ -2597,11 +2598,11 @@ func TestV1MetadataEndpoint(t *testing.T) {
Spec: componentsV1alpha1.ComponentSpec{
Type: "mock.component1Type",
Version: "v1.0",
Metadata: []componentsV1alpha1.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "actorMockComponent1",
Value: componentsV1alpha1.DynamicValue{
JSON: v1.JSON{Raw: []byte("true")},
Value: commonapi.DynamicValue{
JSON: apiextensionsV1.JSON{Raw: []byte("true")},
},
},
},
......@@ -2614,11 +2615,11 @@ func TestV1MetadataEndpoint(t *testing.T) {
Spec: componentsV1alpha1.ComponentSpec{
Type: "mock.component2Type",
Version: "v1.0",
Metadata: []componentsV1alpha1.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "actorMockComponent2",
Value: componentsV1alpha1.DynamicValue{
JSON: v1.JSON{Raw: []byte("true")},
Value: commonapi.DynamicValue{
JSON: apiextensionsV1.JSON{Raw: []byte("true")},
},
},
},
......@@ -2644,11 +2645,11 @@ func TestV1MetadataEndpoint(t *testing.T) {
},
Spec: httpEndpointsV1alpha1.HTTPEndpointSpec{
BaseURL: "api.test.com",
Headers: []httpEndpointsV1alpha1.Header{
Headers: []commonapi.NameValuePair{
{
Name: "Accept-Language",
Value: httpEndpointsV1alpha1.DynamicValue{
JSON: v1.JSON{Raw: []byte("en-US")},
Value: commonapi.DynamicValue{
JSON: apiextensionsV1.JSON{Raw: []byte("en-US")},
},
},
},
......
......@@ -17,6 +17,7 @@ import (
"fmt"
"testing"
commonapi "github.com/dapr/dapr/pkg/apis/common"
componentsapi "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
"github.com/dapr/dapr/pkg/injector/annotations"
"github.com/dapr/dapr/pkg/injector/patcher"
......@@ -97,9 +98,11 @@ func TestComponentsPatch(t *testing.T) {
{
"patch should not create injectable containers operations when app is scopped but has no annotations",
appName,
[]componentsapi.Component{{
Scopes: []string{appName},
}},
[]componentsapi.Component{
{
Scoped: commonapi.Scoped{Scopes: []string{appName}},
},
},
&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
......@@ -148,7 +151,7 @@ func TestComponentsPatch(t *testing.T) {
}`, componentImage),
},
},
Scopes: []string{appName},
Scoped: commonapi.Scoped{Scopes: []string{appName}},
}},
&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
......
......@@ -267,9 +267,13 @@ func GetSidecarContainer(cfg ContainerConfig) (*corev1.Container, error) {
container.Args = append(container.Args, args...)
}
containerEnv := ParseEnvString(cfg.Annotations[annotations.KeyEnv])
containerEnvKeys, containerEnv := ParseEnvString(cfg.Annotations[annotations.KeyEnv])
if len(containerEnv) > 0 {
container.Env = append(container.Env, containerEnv...)
container.Env = append(container.Env, corev1.EnvVar{
Name: authConsts.EnvKeysEnvVar,
Value: strings.Join(containerEnvKeys, " "),
})
}
// This is a special case that requires administrator privileges in Windows containers
......
......@@ -22,6 +22,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"github.com/dapr/dapr/pkg/injector/annotations"
authConsts "github.com/dapr/dapr/pkg/runtime/security/consts"
)
const (
......@@ -847,6 +848,32 @@ func TestGetSidecarContainer(t *testing.T) {
}
})
t.Run("sidecar container should have env vars injected", func(t *testing.T) {
an := map[string]string{
annotations.KeyEnv: `HELLO=world, CIAO=mondo, BONJOUR=monde`,
}
container, _ := GetSidecarContainer(ContainerConfig{
Annotations: an,
})
expect := map[string]string{
"HELLO": "world",
"CIAO": "mondo",
"BONJOUR": "monde",
authConsts.EnvKeysEnvVar: "HELLO CIAO BONJOUR",
}
found := map[string]string{}
for _, env := range container.Env {
switch env.Name {
case "HELLO", "CIAO", "BONJOUR", authConsts.EnvKeysEnvVar:
found[env.Name] = env.Value
}
}
assert.Equal(t, expect, found)
})
t.Run("sidecar container should specify commands only when ignoreEntrypointTolerations match with the pod", func(t *testing.T) {
testCases := []struct {
name string
......
......@@ -36,7 +36,7 @@ func GetMetricsEnabled(pod metaV1.ObjectMeta) bool {
}
// add env-vars from annotations.
func ParseEnvString(envStr string) []coreV1.EnvVar {
func ParseEnvString(envStr string) ([]string, []coreV1.EnvVar) {
indexes := envRegexp.FindAllStringIndex(envStr, -1)
lastEnd := len(envStr)
parts := make([]string, len(indexes)+1)
......@@ -46,19 +46,21 @@ func ParseEnvString(envStr string) []coreV1.EnvVar {
}
parts[0] = envStr[0:lastEnd]
envKeys := make([]string, 0)
envVars := make([]coreV1.EnvVar, 0)
for _, s := range parts {
pairs := strings.Split(strings.TrimSpace(s), "=")
if len(pairs) != 2 {
continue
}
envKeys = append(envKeys, pairs[0])
envVars = append(envVars, coreV1.EnvVar{
Name: pairs[0],
Value: pairs[1],
})
}
return envVars
return envKeys, envVars
}
// ParseVolumeMountsString parses the annotation and returns volume mounts.
......
......@@ -14,7 +14,6 @@ limitations under the License.
package sidecar
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
......@@ -42,21 +41,24 @@ func TestGetAppID(t *testing.T) {
func TestParseEnvString(t *testing.T) {
testCases := []struct {
testName string
envStr string
expEnvLen int
expEnv []coreV1.EnvVar
testName string
envStr string
expLen int
expKeys []string
expEnv []coreV1.EnvVar
}{
{
testName: "empty environment string.",
envStr: "",
expEnvLen: 0,
expEnv: []coreV1.EnvVar{},
testName: "empty environment string",
envStr: "",
expLen: 0,
expKeys: []string{},
expEnv: []coreV1.EnvVar{},
},
{
testName: "common valid environment string.",
envStr: "ENV1=value1,ENV2=value2, ENV3=value3",
expEnvLen: 3,
testName: "common valid environment string",
envStr: "ENV1=value1,ENV2=value2, ENV3=value3",
expLen: 3,
expKeys: []string{"ENV1", "ENV2", "ENV3"},
expEnv: []coreV1.EnvVar{
{
Name: "ENV1",
......@@ -73,9 +75,10 @@ func TestParseEnvString(t *testing.T) {
},
},
{
testName: "special valid environment string.",
envStr: `HTTP_PROXY=http://myproxy.com, NO_PROXY="localhost,127.0.0.1,.amazonaws.com"`,
expEnvLen: 2,
testName: "environment string with quotes",
envStr: `HTTP_PROXY=http://myproxy.com, NO_PROXY="localhost,127.0.0.1,.amazonaws.com"`,
expLen: 2,
expKeys: []string{"HTTP_PROXY", "NO_PROXY"},
expEnv: []coreV1.EnvVar{
{
Name: "HTTP_PROXY",
......@@ -92,9 +95,9 @@ func TestParseEnvString(t *testing.T) {
for _, tc := range testCases {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
envVars := ParseEnvString(tc.envStr)
fmt.Println(tc.testName) //nolint:forbidigo
assert.Equal(t, tc.expEnvLen, len(envVars))
envKeys, envVars := ParseEnvString(tc.envStr)
assert.Equal(t, tc.expLen, len(envVars))
assert.Equal(t, tc.expKeys, envKeys)
assert.Equal(t, tc.expEnv, envVars)
})
}
......
......@@ -31,6 +31,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
commonapi "github.com/dapr/dapr/pkg/apis/common"
componentsapi "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
configurationapi "github.com/dapr/dapr/pkg/apis/configuration/v1alpha1"
httpendpointsapi "github.com/dapr/dapr/pkg/apis/httpEndpoint/v1alpha1"
......@@ -223,7 +224,7 @@ func processComponentSecrets(ctx context.Context, component *componentsapi.Compo
if err != nil {
return err
}
component.Spec.Metadata[i].Value = componentsapi.DynamicValue{
component.Spec.Metadata[i].Value = commonapi.DynamicValue{
JSON: v1.JSON{
Raw: jsonEnc,
},
......@@ -260,7 +261,7 @@ func processHTTPEndpointSecrets(ctx context.Context, endpoint *httpendpointsapi.
if err != nil {
return err
}
endpoint.Spec.Headers[i].Value = httpendpointsapi.DynamicValue{
endpoint.Spec.Headers[i].Value = commonapi.DynamicValue{
JSON: v1.JSON{
Raw: jsonEnc,
},
......
......@@ -29,6 +29,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/yaml"
commonapi "github.com/dapr/dapr/pkg/apis/common"
componentsapi "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
httpendpointapi "github.com/dapr/dapr/pkg/apis/httpEndpoint/v1alpha1"
resiliencyapi "github.com/dapr/dapr/pkg/apis/resiliency/v1alpha1"
......@@ -69,10 +70,10 @@ func TestProcessComponentSecrets(t *testing.T) {
t.Run("secret ref exists, not kubernetes secret store, no error", func(t *testing.T) {
c := componentsapi.Component{
Spec: componentsapi.ComponentSpec{
Metadata: []componentsapi.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "test1",
SecretKeyRef: componentsapi.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "secret1",
Key: "key1",
},
......@@ -91,10 +92,10 @@ func TestProcessComponentSecrets(t *testing.T) {
t.Run("secret ref exists, kubernetes secret store, secret extracted", func(t *testing.T) {
c := componentsapi.Component{
Spec: componentsapi.ComponentSpec{
Metadata: []componentsapi.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "test1",
SecretKeyRef: componentsapi.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "secret1",
Key: "key1",
},
......@@ -138,10 +139,10 @@ func TestProcessComponentSecrets(t *testing.T) {
t.Run("secret ref exists, default kubernetes secret store, secret extracted", func(t *testing.T) {
c := componentsapi.Component{
Spec: componentsapi.ComponentSpec{
Metadata: []componentsapi.MetadataItem{
Metadata: []commonapi.NameValuePair{
{
Name: "test1",
SecretKeyRef: componentsapi.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "secret1",
Key: "key1",
},
......@@ -559,10 +560,10 @@ func TestProcessHTTPEndpointSecrets(t *testing.T) {
e := httpendpointapi.HTTPEndpoint{
Spec: httpendpointapi.HTTPEndpointSpec{
BaseURL: "http://test.com/",
Headers: []httpendpointapi.Header{
Headers: []commonapi.NameValuePair{
{
Name: "test1",
SecretKeyRef: httpendpointapi.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: "secret1",
Key: "key1",
},
......
......@@ -52,11 +52,11 @@ import (
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/structpb"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"github.com/dapr/dapr/pkg/actors"
commonapi "github.com/dapr/dapr/pkg/apis/common"
componentsV1alpha1 "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
httpEndpointV1alpha1 "github.com/dapr/dapr/pkg/apis/httpEndpoint/v1alpha1"
"github.com/dapr/dapr/pkg/apphealth"
......@@ -79,6 +79,7 @@ import (
"github.com/dapr/dapr/pkg/resiliency"
runtimePubsub "github.com/dapr/dapr/pkg/runtime/pubsub"
"github.com/dapr/dapr/pkg/runtime/security"
authConsts "github.com/dapr/dapr/pkg/runtime/security/consts"
"github.com/dapr/dapr/pkg/runtime/wfengine"
"github.com/dapr/dapr/pkg/scopes"
"github.com/dapr/dapr/utils"
......@@ -1132,9 +1133,9 @@ func (a *DaprRuntime) beginComponentsUpdates() error {
func (a *DaprRuntime) onComponentUpdated(component componentsV1alpha1.Component) bool {
oldComp, exists := a.compStore.GetComponent(component.Spec.Type, component.Name)
newComp, _ := a.processComponentSecrets(component)
_, _ = a.processResourceSecrets(&component)
if exists && reflect.DeepEqual(oldComp.Spec, newComp.Spec) {
if exists && reflect.DeepEqual(oldComp.Spec, component.Spec) {
return false
}
......@@ -1229,16 +1230,13 @@ func (a *DaprRuntime) beginHTTPEndpointsUpdates() error {
func (a *DaprRuntime) onHTTPEndpointUpdated(endpoint httpEndpointV1alpha1.HTTPEndpoint) bool {
oldEndpoint, exists := a.compStore.GetHTTPEndpoint(endpoint.Name)
newEndpoint, _ := a.processHTTPEndpointSecrets(endpoint)
_, _ = a.processResourceSecrets(&endpoint)
if exists && reflect.DeepEqual(oldEndpoint.Spec, newEndpoint.Spec) {
if exists && reflect.DeepEqual(oldEndpoint.Spec, endpoint.Spec) {
return false
}
a.pendingHTTPEndpoints <- endpoint
log.Infof("http endpoint updated for http endpoint named: %s", endpoint.Name)
return true
}
......@@ -1706,7 +1704,7 @@ func (a *DaprRuntime) isAppSubscribedToBinding(binding string) (bool, error) {
return false, nil
}
func isBindingOfDirection(direction string, metadata []componentsV1alpha1.MetadataItem) bool {
func isBindingOfDirection(direction string, metadata []commonapi.NameValuePair) bool {
directionFound := false
for _, m := range metadata {
......@@ -1870,7 +1868,7 @@ func (a *DaprRuntime) initState(s componentsV1alpha1.Component) error {
return rterrors.NewInit(rterrors.CreateComponentFailure, fName, err)
}
if store != nil {
secretStoreName := a.authSecretStoreOrDefault(s)
secretStoreName := a.authSecretStoreOrDefault(&s)
secretStore, _ := a.compStore.GetSecretStore(secretStoreName)
encKeys, encErr := encryption.ComponentEncryptionKey(s, secretStore)
......@@ -2150,7 +2148,7 @@ func (a *DaprRuntime) BulkPublish(req *pubsub.BulkPublishRequest) (pubsub.BulkPu
return runtimePubsub.ApplyBulkPublishResiliency(context.TODO(), req, policyDef, defaultBulkPublisher)
}
func metadataContainsNamespace(items []componentsV1alpha1.MetadataItem) bool {
func metadataContainsNamespace(items []commonapi.NameValuePair) bool {
for _, c := range items {
val := c.Value.String()
if strings.Contains(val, "{namespace}") {
......@@ -2695,8 +2693,8 @@ func (a *DaprRuntime) processHTTPEndpoints() {
if endpoint.Name == "" {
continue
}
newEndpoint, _ := a.processHTTPEndpointSecrets(endpoint)
a.compStore.AddHTTPEndpoint(newEndpoint)
_, _ = a.processResourceSecrets(&endpoint)
a.compStore.AddHTTPEndpoint(endpoint)
}
}
......@@ -2792,8 +2790,7 @@ func (a *DaprRuntime) doProcessOneComponent(category components.Category, comp c
}
func (a *DaprRuntime) preprocessOneComponent(comp *componentsV1alpha1.Component) componentPreprocessRes {
var unreadySecretsStore string
*comp, unreadySecretsStore = a.processComponentSecrets(*comp)
_, unreadySecretsStore := a.processResourceSecrets(comp)
if unreadySecretsStore != "" {
return componentPreprocessRes{
unreadyDependency: componentDependency(components.CategorySecretStore, unreadySecretsStore),
......@@ -2983,17 +2980,69 @@ func (a *DaprRuntime) WaitUntilShutdown() error {
return <-a.shutdownC
}
// Returns the component updated with the secrets applied.
// If the component references a secret store that hasn't been loaded yet, it returns the name of the secret store component as second returned value.
func (a *DaprRuntime) processComponentSecrets(component componentsV1alpha1.Component) (componentsV1alpha1.Component, string) {
// Interface that applies to both Component and HTTPEndpoint resources.
type resourceWithMetadata interface {
Kind() string
GetName() string
GetNamespace() string
GetSecretStore() string
NameValuePairs() []commonapi.NameValuePair
}
func isEnvVarAllowed(key string) bool {
// First, apply a denylist that blocks access to sensitive env vars
key = strings.ToUpper(key)
switch {
case key == "":
return false
case key == "APP_API_TOKEN":
return false
case strings.HasPrefix(key, "DAPR_"):
return false
case strings.Contains(key, " "):
return false
}
// If we have a `DAPR_ENV_KEYS` env var (which is added by the Dapr Injector in Kubernetes mode), use that as allowlist too
allowlist := os.Getenv(authConsts.EnvKeysEnvVar)
if allowlist == "" {
return true
}
// Need to check for the full var, so there must be a space after OR it must be the end of the string, and there must be a space before OR it must be at the beginning of the string
idx := strings.Index(allowlist, key)
if idx >= 0 &&
(idx+len(key) == len(allowlist) || allowlist[idx+len(key)] == ' ') &&
(idx == 0 || allowlist[idx-1] == ' ') {
return true
}
return false
}
// Returns the component or HTTP endpoint updated with the secrets applied.
// If the resource references a secret store that hasn't been loaded yet, it returns the name of the secret store component as second returned value.
func (a *DaprRuntime) processResourceSecrets(resource resourceWithMetadata) (updated bool, secretStoreName string) {
cache := map[string]secretstores.GetSecretResponse{}
for i, m := range component.Spec.Metadata {
if m.SecretKeyRef.Name == "" {
secretStoreName = a.authSecretStoreOrDefault(resource)
metadata := resource.NameValuePairs()
for i, m := range metadata {
// If there's an env var and no value, use that
if !m.HasValue() && m.EnvRef != "" {
if isEnvVarAllowed(m.EnvRef) {
metadata[i].SetValue([]byte(os.Getenv(m.EnvRef)))
} else {
log.Warnf("%s %s references an env variable that isn't allowed: %s", resource.Kind(), resource.GetName(), m.EnvRef)
}
metadata[i].EnvRef = ""
updated = true
continue
}
secretStoreName := a.authSecretStoreOrDefault(component)
if m.SecretKeyRef.Name == "" {
continue
}
// If running in Kubernetes and have an operator client, do not fetch secrets from the Kubernetes secret store as they will be populated by the operator.
// Instead, base64 decode the secret values into their real self.
......@@ -3011,20 +3060,16 @@ func (a *DaprRuntime) processComponentSecrets(component componentsV1alpha1.Compo
continue
}
m.Value = componentsV1alpha1.DynamicValue{
JSON: v1.JSON{
Raw: dec,
},
}
component.Spec.Metadata[i] = m
metadata[i].SetValue(dec)
metadata[i].SecretKeyRef = commonapi.SecretKeyRef{}
updated = true
continue
}
secretStore, ok := a.compStore.GetSecretStore(secretStoreName)
if !ok {
log.Warnf("Component %s references a secret store that isn't loaded: %s", component.Name, secretStoreName)
return component, secretStoreName
log.Warnf("%s %s references a secret store that isn't loaded: %s", resource.Kind(), resource.GetName(), secretStoreName)
return updated, secretStoreName
}
resp, ok := cache[m.SecretKeyRef.Name]
......@@ -3033,7 +3078,7 @@ func (a *DaprRuntime) processComponentSecrets(component componentsV1alpha1.Compo
r, err := secretStore.GetSecret(context.TODO(), secretstores.GetSecretRequest{
Name: m.SecretKeyRef.Name,
Metadata: map[string]string{
"namespace": component.ObjectMeta.Namespace,
"namespace": resource.GetNamespace(),
},
})
if err != nil {
......@@ -3051,109 +3096,18 @@ func (a *DaprRuntime) processComponentSecrets(component componentsV1alpha1.Compo
val, ok := resp.Data[secretKeyName]
if ok && val != "" {
component.Spec.Metadata[i].Value = componentsV1alpha1.DynamicValue{
JSON: v1.JSON{
Raw: []byte(val),
},
}
metadata[i].SetValue([]byte(val))
metadata[i].SecretKeyRef = commonapi.SecretKeyRef{}
updated = true
}
cache[m.SecretKeyRef.Name] = resp
}
return component, ""
return updated, ""
}
// Returns the http endpoint updated with the secrets applied.
// If the http endpoint references a secret store that hasn't been loaded yet, it returns the name of the secret store component as second returned value.
func (a *DaprRuntime) processHTTPEndpointSecrets(endpoint httpEndpointV1alpha1.HTTPEndpoint) (httpEndpointV1alpha1.HTTPEndpoint, string) {
cache := map[string]secretstores.GetSecretResponse{}
for i, header := range endpoint.Spec.Headers {
if header.SecretKeyRef.Name == "" {
continue
}
secretStoreName := a.authSecretStoreOrDefault(endpoint)
// If running in Kubernetes and have an operator client, do not fetch secrets from the Kubernetes secret store as they will be populated by the operator.
// Instead, base64 decode the secret values into their real self.
if a.operatorClient != nil && secretStoreName == secretstoresLoader.BuiltinKubernetesSecretStore {
var jsonVal string
err := json.Unmarshal(header.Value.Raw, &jsonVal)
if err != nil {
log.Errorf("Error decoding secret: %v", err)
continue
}
dec, err := base64.StdEncoding.DecodeString(jsonVal)
if err != nil {
log.Errorf("Error decoding secret: %v", err)
continue
}
header.Value = httpEndpointV1alpha1.DynamicValue{
JSON: v1.JSON{
Raw: dec,
},
}
endpoint.Spec.Headers[i] = header
continue
}
secretStore, ok := a.compStore.GetSecretStore(secretStoreName)
if !ok {
log.Warnf("HTTP Endpoint %s references a secret store that isn't loaded: %s", endpoint.Name, secretStoreName)
return endpoint, secretStoreName
}
resp, ok := cache[header.SecretKeyRef.Name]
if !ok {
// TODO: cascade context.
r, err := secretStore.GetSecret(context.TODO(), secretstores.GetSecretRequest{
Name: header.SecretKeyRef.Name,
Metadata: map[string]string{
"namespace": endpoint.ObjectMeta.Namespace,
},
})
if err != nil {
log.Errorf("Error getting secret: %v", err)
continue
}
resp = r
}
// Use the SecretKeyRef.Name key if SecretKeyRef.Key is not given
secretKeyName := header.SecretKeyRef.Key
if secretKeyName == "" {
secretKeyName = header.SecretKeyRef.Name
}
val, ok := resp.Data[secretKeyName]
if ok {
endpoint.Spec.Headers[i].Value = httpEndpointV1alpha1.DynamicValue{
JSON: v1.JSON{
Raw: []byte(val),
},
}
}
cache[header.SecretKeyRef.Name] = resp
}
return endpoint, ""
}
func (a *DaprRuntime) authSecretStoreOrDefault(object interface{}) string {
var secretStore string
switch obj := object.(type) {
case componentsV1alpha1.Component:
secretStore = obj.SecretStore
case httpEndpointV1alpha1.HTTPEndpoint:
secretStore = obj.SecretStore
default:
// Handle unsupported types
return ""
}
func (a *DaprRuntime) authSecretStoreOrDefault(resource resourceWithMetadata) string {
secretStore := resource.GetSecretStore()
if secretStore == "" {
switch a.runtimeConfig.Mode {
case modes.KubernetesMode:
......@@ -3387,7 +3341,7 @@ func (a *DaprRuntime) initSecretStore(c componentsV1alpha1.Component) error {
return nil
}
func (a *DaprRuntime) convertMetadataItemsToProperties(items []componentsV1alpha1.MetadataItem) map[string]string {
func (a *DaprRuntime) convertMetadataItemsToProperties(items []commonapi.NameValuePair) map[string]string {
properties := map[string]string{}
for _, c := range items {
val := c.Value.String()
......
此差异已折叠。
......@@ -15,9 +15,11 @@ package consts
/* #nosec. */
const (
// APITokenEnvVar is the environment variable for the api token.
// Env var for the API token.
APITokenEnvVar = "DAPR_API_TOKEN"
AppAPITokenEnvVar = "APP_API_TOKEN"
// APITokenHeader is header name for http/gRPC calls to hold the token.
// Header name for HTTP/gRPC calls to hold the token.
APITokenHeader = "dapr-api-token"
// Name of the variable injected in the daprd container with the list of injected env vars.
EnvKeysEnvVar = "DAPR_ENV_KEYS"
)
......@@ -25,6 +25,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/dapr/components-contrib/workflows"
commonapi "github.com/dapr/dapr/pkg/apis/common"
componentsV1alpha1 "github.com/dapr/dapr/pkg/apis/components/v1alpha1" // This will be removed
"github.com/dapr/kit/logger"
)
......@@ -39,7 +40,7 @@ var ComponentDefinition = componentsV1alpha1.Component{
Spec: componentsV1alpha1.ComponentSpec{
Type: "workflow.dapr",
Version: "v1",
Metadata: []componentsV1alpha1.MetadataItem{},
Metadata: []commonapi.NameValuePair{},
},
}
......
......@@ -19,7 +19,11 @@ spec:
type: bindings.cron
version: v1
metadata:
- name: schedule
value: "@every 1s"
- name: direction
value: input
- name: schedule
envRef: "CRON_SCHEDULE"
- name: direction
value: input
scopes:
- healthapp-http
- healthapp-grpc
- healthapp-h2c
......@@ -64,6 +64,7 @@ func TestMain(m *testing.M) {
AppHealthProbeInterval: 3,
AppHealthProbeTimeout: 200,
AppHealthThreshold: 3,
DaprEnv: `CRON_SCHEDULE="@every 1s"`, // Test envRef for components
AppEnv: map[string]string{
"APP_PORT": "4000",
"CONTROL_PORT": "3000",
......@@ -85,6 +86,7 @@ func TestMain(m *testing.M) {
AppHealthProbeInterval: 3,
AppHealthProbeTimeout: 200,
AppHealthThreshold: 3,
DaprEnv: `CRON_SCHEDULE="@every 1s"`,
AppEnv: map[string]string{
"APP_PORT": "4000",
"CONTROL_PORT": "3000",
......@@ -106,6 +108,7 @@ func TestMain(m *testing.M) {
AppHealthProbeInterval: 3,
AppHealthProbeTimeout: 200,
AppHealthThreshold: 3,
DaprEnv: `CRON_SCHEDULE="@every 1s"`,
AppEnv: map[string]string{
"APP_PORT": "4000",
"CONTROL_PORT": "3000",
......
......@@ -19,6 +19,7 @@ import (
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
commonapi "github.com/dapr/dapr/pkg/apis/common"
v1alpha1 "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
)
......@@ -40,24 +41,24 @@ func NewDaprComponent(client *KubeClient, ns string, comp ComponentDescription)
// toComponentSpec builds the componentSpec for the given ComponentDescription
func (do *DaprComponent) toComponentSpec() *v1alpha1.Component {
metadata := []v1alpha1.MetadataItem{}
metadata := []commonapi.NameValuePair{}
for k, v := range do.component.MetaData {
var item v1alpha1.MetadataItem
var item commonapi.NameValuePair
if v.FromSecretRef == nil {
item = v1alpha1.MetadataItem{
item = commonapi.NameValuePair{
Name: k,
Value: v1alpha1.DynamicValue{
Value: commonapi.DynamicValue{
JSON: v1.JSON{
Raw: []byte(v.Raw),
},
},
}
} else {
item = v1alpha1.MetadataItem{
item = commonapi.NameValuePair{
Name: k,
SecretKeyRef: v1alpha1.SecretKeyRef{
SecretKeyRef: commonapi.SecretKeyRef{
Name: v.FromSecretRef.Name,
Key: v.FromSecretRef.Key,
},
......
......@@ -25,6 +25,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
commonapi "github.com/dapr/dapr/pkg/apis/common"
v1alpha1 "github.com/dapr/dapr/pkg/apis/components/v1alpha1"
"github.com/dapr/dapr/utils"
)
......@@ -340,7 +341,7 @@ func buildServiceObject(namespace string, appDesc AppDescription) *apiv1.Service
}
// buildDaprComponentObject creates dapr component object.
func buildDaprComponentObject(componentName string, typeName string, scopes []string, annotations map[string]string, metaData []v1alpha1.MetadataItem) *v1alpha1.Component {
func buildDaprComponentObject(componentName string, typeName string, scopes []string, annotations map[string]string, metaData []commonapi.NameValuePair) *v1alpha1.Component {
return &v1alpha1.Component{
TypeMeta: metav1.TypeMeta{
Kind: DaprComponentsKind,
......@@ -353,7 +354,7 @@ func buildDaprComponentObject(componentName string, typeName string, scopes []st
Type: typeName,
Metadata: metaData,
},
Scopes: scopes,
Scoped: commonapi.Scoped{Scopes: scopes},
}
}
......
......@@ -9,7 +9,9 @@ endif
# Generate code
code-generate: controller-gen
$(CONTROLLER_GEN) object:headerFile="./tools/boilerplate.go.txt" \
crd:trivialVersions=true crd:crdVersions=v1 paths="./pkg/apis/..." output:crd:artifacts:config=config/crd/bases
crd:crdVersions=v1 paths="./pkg/apis/..." output:crd:artifacts:config=config/crd/bases
$(CONTROLLER_GEN) object:headerFile="./tools/boilerplate.go.txt" \
paths="./pkg/apis/..."
# find or download controller-gen
# download controller-gen if necessary
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册