$ oc edit <hosted_cluster_name> -n <hosted_cluster_namespace>
OpenShift Container Platform控制平面包含一个内置的OAuth服务器。您可以获取OAuth访问令牌以对OpenShift Container Platform API进行身份验证。创建托管集群后,您可以通过指定身份提供程序来配置OAuth。
您可以使用OpenID Connect身份提供程序 (oidc
) 为托管集群配置内部OAuth服务器。
您可以为以下受支持的身份提供程序配置OAuth
oidc
htpasswd
keystone
ldap
basic-authentication
request-header
github
gitlab
google
在OAuth配置中添加任何身份提供程序都会删除默认的kubeadmin
用户提供程序。
配置身份提供程序时,必须提前在托管集群中配置至少一个 |
您已创建托管集群。
通过运行以下命令编辑托管集群上的HostedCluster
自定义资源 (CR)
$ oc edit <hosted_cluster_name> -n <hosted_cluster_namespace>
使用以下示例在HostedCluster
CR中添加OAuth配置
apiVersion: hypershift.openshift.io/v1alpha1
kind: HostedCluster
metadata:
name: <hosted_cluster_name> (1)
namespace: <hosted_cluster_namespace> (2)
spec:
configuration:
oauth:
identityProviders:
- openID: (3)
claims:
email: (4)
- <email_address>
name: (5)
- <display_name>
preferredUsername: (6)
- <preferred_username>
clientID: <client_id> (7)
clientSecret:
name: <client_id_secret_name> (8)
issuer: https://example.com/identity (9)
mappingMethod: lookup (10)
name: IAM
type: OpenID
1 | 指定托管集群名称。 |
2 | 指定托管集群命名空间。 |
3 | 此提供程序名称作为身份声明的值的前缀,以形成身份名称。提供程序名称也用于构建重定向 URL。 |
4 | 定义用作电子邮件地址的属性列表。 |
5 | 定义用作显示名称的属性列表。 |
6 | 定义用作首选用户名的一系列属性。 |
7 | 定义在OpenID提供程序中注册的客户端的ID。您必须允许客户端重定向到https://oauth-openshift.apps.<cluster_name>.<cluster_domain>/oauth2callback/<idp_provider_name> URL。 |
8 | 定义在OpenID提供程序中注册的客户端的密钥。 |
9 | OpenID规范中描述的颁发者标识符。您必须使用不带查询或片段组件的https 。 |
10 | 定义控制如何在此提供程序的身份和User 对象之间建立映射的映射方法。 |
保存文件以应用更改。
您可以使用OpenShift Container Platform Web控制台为托管集群配置内部OAuth服务器。
您可以为以下受支持的身份提供程序配置OAuth
oidc
htpasswd
keystone
ldap
basic-authentication
request-header
github
gitlab
google
在OAuth配置中添加任何身份提供程序都会删除默认的kubeadmin
用户提供程序。
配置身份提供程序时,必须提前在托管集群中配置至少一个 |
您已以具有cluster-admin
权限的用户身份登录。
您已创建托管集群。
导航到主页 → API资源管理器。
使用按类型筛选框搜索您的HostedCluster
资源。
单击要编辑的HostedCluster
资源。
单击实例选项卡。
单击托管集群名称条目旁边的选项菜单,然后单击编辑HostedCluster。
在YAML文件中添加OAuth配置
spec:
configuration:
oauth:
identityProviders:
- openID: (1)
claims:
email: (2)
- <email_address>
name: (3)
- <display_name>
preferredUsername: (4)
- <preferred_username>
clientID: <client_id> (5)
clientSecret:
name: <client_id_secret_name> (6)
issuer: https://example.com/identity (7)
mappingMethod: lookup (8)
name: IAM
type: OpenID
1 | 此提供程序名称作为身份声明的值的前缀,以形成身份名称。提供程序名称也用于构建重定向 URL。 |
2 | 定义用作电子邮件地址的属性列表。 |
3 | 定义用作显示名称的属性列表。 |
4 | 定义用作首选用户名的一系列属性。 |
5 | 定义在OpenID提供程序中注册的客户端的ID。您必须允许客户端重定向到https://oauth-openshift.apps.<cluster_name>.<cluster_domain>/oauth2callback/<idp_provider_name> URL。 |
6 | 定义在OpenID提供程序中注册的客户端的密钥。 |
7 | OpenID规范中描述的颁发者标识符。您必须使用不带查询或片段组件的https 。 |
8 | 定义控制如何在此提供程序的身份和User 对象之间建立映射的映射方法。 |
单击保存。
要了解有关受支持身份提供程序的更多信息,请参阅身份验证和授权中的"了解身份提供程序配置"。
您可以使用 Amazon Web Services (AWS) 托管集群中的 Cloud Credential Operator (CCO) 为组件分配提供短期、有限权限安全凭据的 IAM 角色。默认情况下,CCO 在托管控制平面中运行。
CCO 仅支持 AWS 托管集群的手动模式。默认情况下,托管集群配置为手动模式。管理集群可能使用除手动模式以外的其他模式。 |
您可以验证 Cloud Credential Operator (CCO) 是否在您的托管控制平面中正确运行。
您已在 Amazon Web Services (AWS) 上配置了托管集群。
通过运行以下命令,验证 CCO 是否以手动模式在您的托管集群中配置
$ oc get cloudcredentials <hosted_cluster_name> -n <hosted_cluster_namespace> -o=jsonpath={.spec.credentialsMode}
Manual
通过运行以下命令,验证serviceAccountIssuer
资源的值是否不为空
$ oc get authentication cluster --kubeconfig <hosted_cluster_name>.kubeconfig -o jsonpath --template '{.spec.serviceAccountIssuer }'
https://aos-hypershift-ci-oidc-29999.s3.us-east-2.amazonaws.com/hypershift-ci-29999
作为设计您的项目以在 Operator Lifecycle Manager (OLM) 上运行的 Operator 作者,您可以通过自定义您的项目以支持 Cloud Credential Operator (CCO),使您的 Operator 能够对启用 STS 的 OpenShift Container Platform 集群上的 AWS 进行身份验证。
使用此方法,Operator 负责并需要 RBAC 权限才能创建CredentialsRequest
对象和读取生成的Secret
对象。
默认情况下,与 Operator 部署相关的 Pod 会挂载 |
OpenShift Container Platform 4.14 或更高版本
处于 STS 模式下的集群
基于 OLM 的 Operator 项目
更新您的 Operator 项目的ClusterServiceVersion
(CSV) 对象
确保您的 Operator 具有创建CredentialsRequests
对象的 RBAC 权限
clusterPermissions
列表示例# ...
install:
spec:
clusterPermissions:
- rules:
- apiGroups:
- "cloudcredential.openshift.io"
resources:
- credentialsrequests
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
添加以下注释以声明支持此使用 AWS STS 的基于 CCO 的工作流的方法
# ...
metadata:
annotations:
features.operators.openshift.io/token-auth-aws: "true"
更新您的 Operator 项目代码
从Subscription
对象在 Pod 上设置的环境变量中获取角色 ARN。例如
// Get ENV var
roleARN := os.Getenv("ROLEARN")
setupLog.Info("getting role ARN", "role ARN = ", roleARN)
webIdentityTokenPath := "/var/run/secrets/openshift/serviceaccount/token"
确保您已准备好要修补和应用的CredentialsRequest
对象。例如
CredentialsRequest
对象创建示例import (
minterv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var in = minterv1.AWSProviderSpec{
StatementEntries: []minterv1.StatementEntry{
{
Action: []string{
"s3:*",
},
Effect: "Allow",
Resource: "arn:aws:s3:*:*:*",
},
},
STSIAMRoleARN: "<role_arn>",
}
var codec = minterv1.Codec
var ProviderSpec, _ = codec.EncodeProviderSpec(in.DeepCopyObject())
const (
name = "<credential_request_name>"
namespace = "<namespace_name>"
)
var CredentialsRequestTemplate = &minterv1.CredentialsRequest{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: "openshift-cloud-credential-operator",
},
Spec: minterv1.CredentialsRequestSpec{
ProviderSpec: ProviderSpec,
SecretRef: corev1.ObjectReference{
Name: "<secret_name>",
Namespace: namespace,
},
ServiceAccountNames: []string{
"<service_account_name>",
},
CloudTokenPath: "",
},
}
或者,如果您是从 YAML 格式的CredentialsRequest
对象开始(例如,作为您 Operator 项目代码的一部分),您可以以不同的方式处理它
CredentialsRequest
对象创建示例// CredentialsRequest is a struct that represents a request for credentials
type CredentialsRequest struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Metadata struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
} `yaml:"metadata"`
Spec struct {
SecretRef struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
} `yaml:"secretRef"`
ProviderSpec struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
StatementEntries []struct {
Effect string `yaml:"effect"`
Action []string `yaml:"action"`
Resource string `yaml:"resource"`
} `yaml:"statementEntries"`
STSIAMRoleARN string `yaml:"stsIAMRoleARN"`
} `yaml:"providerSpec"`
// added new field
CloudTokenPath string `yaml:"cloudTokenPath"`
} `yaml:"spec"`
}
// ConsumeCredsRequestAddingTokenInfo is a function that takes a YAML filename and two strings as arguments
// It unmarshals the YAML file to a CredentialsRequest object and adds the token information.
func ConsumeCredsRequestAddingTokenInfo(fileName, tokenString, tokenPath string) (*CredentialsRequest, error) {
// open a file containing YAML form of a CredentialsRequest
file, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer file.Close()
// create a new CredentialsRequest object
cr := &CredentialsRequest{}
// decode the yaml file to the object
decoder := yaml.NewDecoder(file)
err = decoder.Decode(cr)
if err != nil {
return nil, err
}
// assign the string to the existing field in the object
cr.Spec.CloudTokenPath = tokenPath
// return the modified object
return cr, nil
}
目前不支持向 Operator 包中添加 |
在 Operator 初始化期间,将角色 ARN 和 Web 身份令牌路径添加到凭据请求并应用它
CredentialsRequest
对象的示例// apply CredentialsRequest on install
credReq := credreq.CredentialsRequestTemplate
credReq.Spec.CloudTokenPath = webIdentityTokenPath
c := mgr.GetClient()
if err := c.Create(context.TODO(), credReq); err != nil {
if !errors.IsAlreadyExists(err) {
setupLog.Error(err, "unable to create CredRequest")
os.Exit(1)
}
}
确保您的 Operator 可以等待 CCO 从凭据请求中显示Secret
对象,如下例所示,它与您在 Operator 中协调的其他项目一起调用
Secret
对象的示例// WaitForSecret is a function that takes a Kubernetes client, a namespace, and a v1 "k8s.io/api/core/v1" name as arguments
// It waits until the secret object with the given name exists in the given namespace
// It returns the secret object or an error if the timeout is exceeded
func WaitForSecret(client kubernetes.Interface, namespace, name string) (*v1.Secret, error) {
// set a timeout of 10 minutes
timeout := time.After(10 * time.Minute) (1)
// set a polling interval of 10 seconds
ticker := time.NewTicker(10 * time.Second)
// loop until the timeout or the secret is found
for {
select {
case <-timeout:
// timeout is exceeded, return an error
return nil, fmt.Errorf("timed out waiting for secret %s in namespace %s", name, namespace)
// add to this error with a pointer to instructions for following a manual path to a Secret that will work on STS
case <-ticker.C:
// polling interval is reached, try to get the secret
secret, err := client.CoreV1().Secrets(namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
// secret does not exist yet, continue waiting
continue
} else {
// some other error occurred, return it
return nil, err
}
} else {
// secret is found, return it
return secret, nil
}
}
}
}
1 | timeout 值基于对 CCO 检测添加的CredentialsRequest 对象并生成Secret 对象的快慢的估计。您可能需要考虑缩短时间或为可能想知道 Operator 为什么尚未访问云资源的集群管理员创建自定义反馈。 |
通过读取 CCO 从凭据请求创建的密钥并创建包含该密钥数据的 AWS 配置文件来设置 AWS 配置
func SharedCredentialsFileFromSecret(secret *corev1.Secret) (string, error) {
var data []byte
switch {
case len(secret.Data["credentials"]) > 0:
data = secret.Data["credentials"]
default:
return "", errors.New("invalid secret for aws credentials")
}
f, err := ioutil.TempFile("", "aws-shared-credentials")
if err != nil {
return "", errors.Wrap(err, "failed to create file for shared credentials")
}
defer f.Close()
if _, err := f.Write(data); err != nil {
return "", errors.Wrapf(err, "failed to write credentials to %s", f.Name())
}
return f.Name(), nil
}
假设密钥存在,但在使用此密钥时,您的 Operator 代码应等待并重试,以便为 CCO 创建密钥留出时间。 此外,等待时间最终应该超时并警告用户 OpenShift Container Platform 集群版本(以及 CCO)可能是一个较早的版本,不支持使用 STS 检测的 |
配置 AWS SDK 会话,例如
sharedCredentialsFile, err := SharedCredentialsFileFromSecret(secret)
if err != nil {
// handle error
}
options := session.Options{
SharedConfigState: session.SharedConfigEnable,
SharedConfigFiles: []string{sharedCredentialsFile},
}