k8s权限控制RBAC

k8s安全控制、授权管理介绍 两者最终都是面向kubernetes的单独位于kubernetes外的用户账号kubernetes管理账号,为pod中的服务进程在访问kubernete时提供身份标识我是以kubeadm安装的kubernetes,主要是用到rbac的角色访问控制。 阅读详情

1、简介

kubernetes集群所有的交互都是通过apiServer来进行的,因此k8s对权限的控制就尤其重要。

从1.6版本起,kubernetes默认启用RBAC访问控制策略。RBAC(Role-Based Access Control):基于角色的访问控制

相关概念:

RBAC中4种顶级资源:Role、ClusterRole、RoleBinding、ClusterRoleBinding

  • Role:角色,包含一组权限的规则。没有拒绝规则,只是附加运行。Namespace隔离,只作用于命名空间

  • ClusterRole:和Role的区别,Role只作用于命名空间内,ClusterRole作用于整个集群,也就是所有Namespace

  • RoleBinding:作用于命名空间内,将ClusterRole或Role绑定于User、Group或ServiceAccount

  • ClusterRoleBinding:作用于整个集群,将ClusterRole或Role绑定于User、Group或ServiceAccount

  • 用户:k8s有两种用户:User和ServiceAccount。其中user是给人来使用的,serviceAccount是给进程来使用的。当一个运行在k8s中的进程需要访问apiServer时,我们就需要给其创建一个serviceAccount,并通过role来限制这个serviceAccount的权限,最后通过rolebinding将role绑定到该serviceAccount上。

可以通过kubectl create 来创建role、clusterrole、rolebinding、clusterrolebinding和serviceAccount

在这里插入图片描述

 

1.1 创建serviceAccount

命令如下:

kubectl create sa <Name>
或
kubectl create serviceAccount <Name>


# 例如
kubectl create serviceaccount my-sa
  • Name: 要创建的serviceAccount的名字

 

1.2 创建role

命令如下:

kubectl create role <RoleName> [options]

常用options:
    --resource=[]:
        Resource that the rule applies to
    --verb=[]:
        Verb that applies to the resources contained in the rule
        
# 例如: 创建一个名为role-test的role,可以操作的资源为pod和deployment,可以进行的操作为get,create,list,watch,update,delete
kubectl create role role-test --resource=pod,deployment --verb=get,create,list,watch,update,delete
  • RoleName:要创建的role的名字
  • –resource:指定该role可以操作的资源,例如pod、deployment、service等
  • –verb:指定该role对资源可以进行的操作,例如get、list、watch、update、create、delete、patch等

 

1.3 创建rolebinding

命令如下:

kubectl create rolebinding <RBNAME> [options]

常用options:
   --role='':
        Role this RoleBinding should reference
   --serviceaccount=[]:
        Service accounts to bind to the role, in the format <namespace>:<name>. The flag can be
        repeated to add multiple service accounts.
   --clusterrole='':
        ClusterRole this RoleBinding should reference

# 例如 将role-test和my-sa进行绑定,绑定后my-sa就拥有了role中定义的规则
kubectl create rolebinding rb-test --role=role-test --serviceaccount=my-sa
  • RBNAME:rolebinding的名字
  • –role:要进行绑定的role的name
  • –clusterrole:要进行绑定的clusterrole的name
  • –serviceaccount:要进行绑定的serviceaccount的name

 

2、实战案例

下面将使用client go编写一个程序,该程序可以对default命名空间下的deploy进行create、update、get和delete的操作。最后将该程序部署到k8s的deploy中。

代码如下:

package main

import (
	"context"
	"github.com/gin-gonic/gin"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	appsresv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/util/retry"
	"k8s.io/klog/v2"
	"net/http"
)

func main() {

	// 1、创建配置文件,由于要在k8s中运行,使用InClusterConfig可以获取到serviceAccount的配置
	config, err := rest.InClusterConfig()
	if err != nil {
		panic(err)
	}

	// 2、创建clientset
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}
	deployClient := clientset.AppsV1().Deployments(corev1.NamespaceDefault)

	r := gin.Default()
	r.PUT("/deploy", func(c *gin.Context) {
		if err := CreateDeploy(deployClient); err != nil {
			JsonErr(c, err)
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"message": "success",
		})
	})

	r.POST("/deploy", func(c *gin.Context) {
		if err := UpdateDeploy(deployClient); err != nil {
			JsonErr(c, err)
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"message": "success",
		})
	})

	r.GET("/deploy", func(c *gin.Context) {
		if dep, err := ListDeploy(deployClient); err != nil {
			JsonErr(c, err)
		} else {
			if dep == nil {
				c.JSON(http.StatusOK, gin.H{
					"message": "success",
					"data":    "nil",
				})
				return
			}
			c.JSON(http.StatusOK, gin.H{
				"message": "success",
				"data": map[string]interface{}{
					"name":     dep.Name,
					"replicas": dep.Spec.Replicas,
					"image":    dep.Spec.Template.Spec.Containers[0].Image,
				},
			})
		}
	})

	r.DELETE("/deploy", func(c *gin.Context) {
		if err := DeleteDeploy(deployClient); err != nil {
			JsonErr(c, err)
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"message": "success",
		})
	})

	r.Run(":9000")
}

func JsonErr(ctx *gin.Context, err error) {
	ctx.JSON(http.StatusOK, gin.H{
		"message": err.Error(),
	})
}

func CreateDeploy(client appsresv1.DeploymentInterface) error {
	klog.Info("CreateDeploy...........")
	replicas := int32(2)
	deploy := appsv1.Deployment{
		TypeMeta: v1.TypeMeta{
			Kind:       "Deployment",
			APIVersion: "apps/v1",
		},
		ObjectMeta: v1.ObjectMeta{
			Name:      "deploy-nginx-demo",
			Namespace: corev1.NamespaceDefault,
		},
		Spec: appsv1.DeploymentSpec{
			Replicas: &replicas,
			Selector: &v1.LabelSelector{
				MatchLabels: map[string]string{
					"app": "nginx",
				},
			},
			Template: corev1.PodTemplateSpec{
				ObjectMeta: v1.ObjectMeta{
					Name: "nginx",
					Labels: map[string]string{
						"app": "nginx",
					},
				},
				Spec: corev1.PodSpec{
					Containers: []corev1.Container{
						{
							Name:  "web",
							Image: "nginx:1.12",
							Ports: []corev1.ContainerPort{
								{
									Protocol:      corev1.ProtocolTCP,
									ContainerPort: 80,
								},
							},
						},
					},
				},
			},
		},
	}

	dep, err := client.Create(context.Background(), &deploy, v1.CreateOptions{})
	if err != nil {
		klog.Errorf("create deployment error:%v", err)
		return err
	}
	klog.Infof("create deployment success, name:%s", dep.Name)

	return nil
}

func UpdateDeploy(client appsresv1.DeploymentInterface) error {
	klog.Info("UpdateDeploy...........")
	// 当有多个客户端对同一个资源进行操作时,会发送错误。使用RetryOnConflict来重试,重试相关参数由DefaultRetry来提供
	err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
		// 查询要更新的deploy
		deploy, err := client.Get(context.Background(), "deploy-nginx-demo", v1.GetOptions{})
		if err != nil {
			klog.Errorf("can't get deployment, err:%v", err)
			return nil
		}

		// 修改参数后进行更新
		replicas := int32(1)
		deploy.Spec.Replicas = &replicas
		deploy.Spec.Template.Spec.Containers[0].Image = "nginx:1.13"

		_, err = client.Update(context.Background(), deploy, v1.UpdateOptions{})
		if err != nil {
			klog.Errorf("update deployment error, err:%v", err)
		}
		return err
	})

	if err != nil {
		klog.Errorf("update deployment error, err:%v", err)
		return err
	} else {
		klog.Infof("update deployment success")
	}

	return nil
}

func ListDeploy(client appsresv1.DeploymentInterface) (*appsv1.Deployment, error) {
	klog.Info("ListDeploy...........")
	deplist, err := client.List(context.Background(), v1.ListOptions{})
	if err != nil {
		klog.Errorf("list deployment error, err:%v", err)
		return nil, err
	}

	for _, dep := range deplist.Items {
		klog.Infof("deploy name:%s, replicas:%d, container image:%s", dep.Name, *dep.Spec.Replicas, dep.Spec.Template.Spec.Containers[0].Image)
	}
	if deplist != nil && len(deplist.Items) > 0 {
		return &deplist.Items[0], nil
	}

	return nil, nil
}

func DeleteDeploy(client appsresv1.DeploymentInterface) error {
	klog.Info("DeleteDeploy...........")
	// 删除策略
	deletePolicy := v1.DeletePropagationForeground
	err := client.Delete(context.Background(), "deploy-nginx-demo", v1.DeleteOptions{PropagationPolicy: &deletePolicy})
	if err != nil {
		klog.Errorf("delete deployment error, err:%v", err)
		return err
	} else {
		klog.Info("delete deployment success")
	}

	return nil
}

 

dockerfile:

FROM golang:1.18 AS builder

WORKDIR /app
COPY . .
ENV GOPROXY https://goproxy.cn
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -o app main.go


FROM alpine

WORKDIR /app

COPY --from=builder /app/app .

EXPOSE 9000

CMD ["./app"]

 

1、使用dockerfile构建镜像:

docker build -t incluster_test .

2、使用K8S的deployment来部署,创建deploy.yaml

# 小技巧,自己写yaml文件太麻烦,我们可以使用命令来生成,然后再修改
kubectl create deploy incluster-test --replicas=1 --image=incluster_test --dry-run=client -o yaml > deploy.yaml
# 对deploy中内容进行修改

apiVersion: apps/v1
kind: Deployment
metadata:
  name: incluster-test
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      serviceAccountName: incluster-test-sa
      containers:
      - name: test-incluster
        image: incluster_test
        imagePullPolicy: Never
        ports:
        - containerPort: 9000

3、创建serviceAccount:创建role目录,在role中创建sa.yaml

mkdir role
cd role
kubectl create sa incluster-test-sa --dry-run=client -o yaml > sa.yaml

4、创建role:创建role.yaml

kubectl create role incluster-test-role --resource=deployment --verb=create,get,list,update,delete --dry-run=client -o yaml > role.yaml

5、创建rolebinding:创建rb.yaml

kubectl create rolebinding incluster-test-rb --serviceaccount=default:incluster-test-sa --role=incluster-test-role --dry-run=client -o yaml > rb.yaml

6、部署:

# 在role目录中执行下面命令,创建serviceAccount、role和rolebinding
kubectl create -f .

[root@master role]# kubectl create -f .
rolebinding.rbac.authorization.k8s.io/incluster-test-rb created
role.rbac.authorization.k8s.io/incluster-test-role created
serviceaccount/incluster-test-sa created

# 部署deployment
[root@master test_incluster]# kubectl create -f deploy.yaml
deployment.apps/incluster-test created

# 查看deploy和pod
[root@master test_incluster]# kubectl get deploy,pod
NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/incluster-test   1/1     1            1           98s

NAME                                  READY   STATUS    RESTARTS   AGE
pod/incluster-test-779cc788f4-dfntb   1/1     Running   0          98s

# 使用curl来访问
[root@master test_incluster]# kubectl get pod -o wide
NAME                              READY   STATUS    RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES
incluster-test-779cc788f4-dfntb   1/1     Running   0          2m6s   10.244.0.40   master   <none>           <none>

# 使用curl,PUT方法来创建deploy
[root@master test_incluster]# curl -X PUT 10.244.0.40:9000/deploy
{"message":"success"}

# GET方法查看Pod
[root@master test_incluster]# curl  10.244.0.40:9000/deploy
{"data":{"image":"nginx:1.12","name":"deploy-nginx-demo","replicas":2},"message":"success"}

# POST方法更新Pod
[root@master test_incluster]# curl -X POST 10.244.0.40:9000/deploy
{"message":"success"}
[root@master test_incluster]# curl  10.244.0.40:9000/deploy
{"data":{"image":"nginx:1.13","name":"deploy-nginx-demo","replicas":1},"message":"success"}

# DELETE方法删除Pod
[root@master test_incluster]# curl -X DELETE 10.244.0.40:9000/deploy
{"message":"success"}
K8S常用指令(必备) 3. kubectl autoscale deployment {name} --cpu-percent={percent} --min={min} --max={max} - 自动扩缩deployment的pod数量。2. kubectl expose deployment {name} --port={port} --target-port={targetport} --type={type} - 创建service。 阅读详情

相关推荐

k8s RBAC 多租户权限控制实现

更多kubernetes文章:k8s专栏目录访问到权限分两部分1.Authenticating认证授权配置由kube-apiserver管理这里使用的是 Static Password File 方式。apiserver启动yaml里配置basic-auth-file即可,容器启动apiserver的话要注意这个文件需要是在容器内能访问到的。(可以通过挂载文件,或者在已经挂载的路径里增加配置文件)...

zhd930818的博客 8098

kubernetes(k8s)之rbac权限管理详解

kubernetes(k8s)之rabc权限

qq_44823950的博客 2614

二十、K8S-1-权限管理RBAC详解

在RBAC API中,通过如下步骤进行授权在定义角色时会指定此角色对于资源的访问控制规则Role:角色,包含一组权限的规则,没有拒绝规则,只是附加运行,namespaces隔离,只作用于命名空间。授权特定命名空间的访问权限ClusterRole:和Role的区别,Role只作用于命名空间内,ClusterRole作用于整个集群,也就是所有Namespace。

爱吃西红柿的博客 2428

kubernetes--RBAC权限管理

calico/coredns/dashboard >>都需要访问apiserver简称SA,是一种用于让程序访问K8sAPI的服务账号1.当创建namespace时,会自动创建一个名为default的SA,这个SA没有绑定任何权限2.当default SA创建时,会自动创建一个default-token-xxx的secret,并自动关联到SA。

m0_57911290的博客 9774

Kubernetes 探秘:基于角色的权限控制(RBAC)深度解析

管理员首先定义不同的角色,明确每个角色所拥有的对各种资源的操作权限。使用 YAML 文件来定义 Role 或 ClusterRole,例如:# 定义一个命名空间内的 Rolekind: Rolemetadata:rules:# 定义一个集群范围的 ClusterRolemetadata:rules:基于角色的权限控制(RBAC)是 Kubernetes 集群安全管理的重要组成部分。

yonggeit的博客 3046

k8s权限控制RBAC中的clusterrole serviceaccount rolebinding 有什么作用

在 Kubernetes 的权限控制模型中,RBAC(基于角色的访问控制,Role-Based Access Control)用于管理对集群资源的访问权限。和是其中的关键概念。

u010674101的专栏 577

Kubernetes(K8S) 之 RBAC 权限控制

Kubernetes 权限控制 RBAC 1. Kubernetes中的用户 User:通常是人来使用,而ServiceAccount是某个服务/资源/程序使用的User独立在K8S之外,也就是说User是可以作用于全局的,在任何命名空间都可被认知,并且需要在全局唯一 Service Account:而ServiceAccount作为K8S内部的某种资源,是存在于某个命名空间之中的,在不同命名空间中的同名ServiceAccount被认为是不同的资源。 1.1. 用户验证 尽管K8S认知用户靠的只是用户的名

li1121567428的博客 595

Rocky Linux 9 离线环境Docker部署实战:从依赖打包到服务启动

本文提供了一份详尽的Rocky Linux 9离线环境Docker部署实战指南。针对无法访问外网的生产或内网服务器,文章详细讲解了如何在联网跳板机上下载Docker二进制包及所有系统依赖RPM包,并完成打包。随后,手把手指导在离线服务器上进行依赖安装、二进制文件部署、systemd服务配置、SELinux与防火墙调优,最终实现Docker服务的成功启动与验证。

weixin_28363123的博客 138

k8s RBAC权限控制

使用k8s RBAC权限控制

2401_86274572的博客 1403

SAP ERP销售应收&成本科目确定

ERP作为业财一体软件,其中最核心的就是业务与财务模块的自动集成,无需财务进行手工做账,提高工作效率的同时降低人工操作产生的误差。今天浅浅的分享一下SD模块生成会计凭证时,借贷项确定的系统配置。一般项目上借贷项、科目都有FICO提供,但是具体的集成配置是在SD这边。

weixin_43657667的博客 1569

Ubuntu 20.04 系统备份和还原

最近大家Ubuntu开发环境,经常出现搭着搭着系统就挂了,于是开始琢磨了Ubuntu系统的备份和还原,以备不时之需,Linux环境搭建实在是有点太细,好多情况下,就算曾经搭建过一遍,再次搭建有些包还是忘了安装,做好备份是十分必要的。 经过了一番研究,Ubuntu备份有很多方式:根目录tar、dd、Systemback(1.0版本已经不维护了,2.0版本收费)等等,最终决定使用 —— Timesift, 因为方便一些。 文章参考:小马虎的救星——Timeshift Timeshift Timeshift,是L

Z_Paper的博客 2万+

Kubernetes RBAC权限控制:从入门到实战

Role:作用于单个命名空间的权限规则。:作用于整个集群的权限规则(如节点管理、集群级操作)。示例:定义一个只允许读取Pod的角色kind: Rolemetadata:namespace: default # 限定命名空间rules:- apiGroups: [""] # 核心API组(Pod属于此组)resources: ["pods"] # 允许操作的资源类型verbs: ["get", "list", "watch"] # 可执行的操作RBAC是Kubernetes安全体系的基石。

like21a的博客 895

分析国外几款主流蜜罐产品看欺骗诱捕技术的应用脉络

网络安全的本质是攻防对抗,更本质的其实是人与人心智与技术的全面较量。 欺骗诱捕技术作为攻防对抗技术中比较特殊的技术,能够使防守方更多掌握对抗中的主动权,诱导攻击,迫使攻击者耗费精力的同时,留下丰富的攻击信息。究其本质,欺骗诱捕技术更深层次考验的不止是技术的能力,还有对于攻击者作为人的理解。 国外主流蜜罐产品分析 根据MarketsandMarkets《欺骗技术市场规模、份额和2021年全球市场预测》中提到的欺骗诱捕技术全球主要供应商及产品,我们分析了几款国外主流的蜜罐产品,希望更清晰看到欺骗诱捕技术应

cdyunaq的博客 1310

Kubernetes - 实战:一文详解ServiceAccount及RBAC权限控制

在 Kubernetes 中,ServiceAccount 和 RBAC(Role-Based Access Control)是用于控制集群内资源访问权限的重要组成部分。

qq_33240556的博客 1334

专栏三:解析spatialCNV的使用

文章Spatially resolved clonal copy number alterations in benign and malignant tissue发在natur

m0_58549466的博客 1252

基于半经验模型的熔断器燃弧过程计算与分析

本文针对1200V/1250A熔断器建立电弧燃烧半经验模型,通过ANSYS计算弧前时间,结合熔体烧蚀、石英砂烧蚀等物理过程简化建模。模型引入电导率随温度变化函数,利用Matlab拟合实验数据确定参数。分析表明:熔体宽度和节距增加会提高弧压峰值并缩短过零时间;总长固定时,断口数和节距影响较小。弧压峰值需控制在额定电压3倍内,过零时间需满足安全裕度。通过Python代码复现了电弧电导率模型、能量平衡方程及弧压计算,验证了熔体结构尺寸对电弧特性的影响规律。

huanghm88的专栏 259

Kubernetes CKA实战:RBAC权限控制详解与模拟练习

它通过四个核心对象实现权限管理:Role定义权限规则,ClusterRole适用于集群范围,RoleBinding将角色绑定到主体,ServiceAccount作为身份凭证。在实际操作中,需要特别注意命名空间隔离性,clusterrolebinding会赋予全局权限,而rolebinding仅在指定命名空间生效。具体实现时,--verb参数指定create操作,--resource明确资源类型列表。验证环节的--as参数模拟了服务账号的权限测试,这是排查RBAC配置问题的常用技巧。

AzureMeadow65的博客 586

MySQL数据库面试题(2022版)

序列号 内容 链接 1 Java基础知识面试题(2022版) https://blog.youkuaiyun.com/qq_43061290/article/details/124023797 2 Java集合容器面试题(2022版) https://blog.youkuaiyun.com/qq_43061290/article/details/124043363 3 Java异常面试题(2022版) https://blog.youkuaiyun.com/qq_43061290/article/details/124....

拉格朗日的学习笔记 1万+

JAVA面试题分享二百四十九:Kubernetes(k8s)权限管理RBAC详解

先复习下 K8s 里的 RBAC 机制。(这时候需要用到 GPT 了。我:Hello ChatGPT,用中文总结下 K8s 里的 RBAC 是个啥。ChatGPT在 Kubernetes 中,RBAC 是一种强大的访问控制机制,用于管理对集群资源的访问权限。RBAC 可以帮助管理员精确地控制用户、ServiceAccount 或其他实体对 Kubernetes API 中资源的操作权限。RBAC 基于角色的授权模型使得管理员可以定义角色和角色绑定,从而实现对不同用户或实体的访问权限控制。

之乎者也·的博客 1107

ABB机器人与S7-1200PLC实现位置坐标数据发送和接收的具体方法

ABB机器人与S7-1200PLC实现位置坐标数据发送和接收的具体方法

Robot_PLC_HMI_Automation 2917

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

K8S认证|CKA题库+答案| 1. 权限控制RBAC

K8S认证 | CKA题库+答案 | 权限控制RBAC

Dances with Cloud Native 2万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Kubernetes — RBAC权限控制

1. 在Kubernetes中,负责完成授权(Authorization)工作的机制,就是RBAC:基于角色的访问控制(Role-Based Access Control)2. “主体”(subject)能够或不能够“操作”(operate)哪个或哪类“对象”(object)。动作的发出者是subject,通常是(User Account),也可以是(Service Account)。“操作”(operate)用于表明执行的具体操作,

qq_41619571的博客 1074

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

云原生安全:容器镜像扫描与 Kubernetes RBAC 权限控制

(Role)

gdfsdfsad的博客 412

authorization权限控制_Kubernetes RBAC角色权限控制

摘选:https://i4t.com/4448.html在Kubernetes中所有的API对象都保存在ETCD里,可是,对这些API对象的操作,却一定是通过访问kube-apiserver实现的。我们需要APIServer来帮助我们授权工作,而在Kubernetes项目中,负责完成授权(Authorization)的工作机制就是RBAC: 基于角色的访问控制 (Role-Based Access...

weixin_39966020的博客 456

hadooprbac_Kubernetes RBAC角色权限控制

在Kubernetes中所有的API对象都保存在ETCD里,可是,对这些API对象的操作,却一定是通过访问kube-apiserver实现的。我们需要APIServer来帮助我们授权工作,而在Kubernetes项目中,负责完成授权(Authorization)的工作机制就是RBAC: 基于角色的访问控制 (Role-Based Access Control)RBAC是基于角色的访问控制 (Rol...

weixin_39789499的博客 147
上一篇: k8s编程operator——(1) client-go基础部分
下一篇: Golang标准库限流器rate使用
CoreDump丶
博客等级 码龄8年 451粉丝 70原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值