17 集群安全

理论基础

在这里插入图片描述
认证:
如上图步骤 1 所示,建立 TLS 后, HTTP 请求将进入认证(Authentication)步骤。认证模块包含客户端证书、密码、普通令牌、引导令牌等。可以指定多个认证模块,在这种情况下,服务器依次尝试每个验证模块,直到其中一个成功。

授权:
如上图的步骤 2 所示,将请求验证为来自特定的用户后,请求必须被鉴权。
请求必须包含请求者的用户名、请求的行为以及受该操作影响的对象。 如果现有策略声明用户有权完成请求的操作,那么该请求被鉴权通过。

准入控制:
如上图的步骤 3 所示,准入控制模块是可以修改或拒绝请求的软件模块。 除鉴权模块可用的属性外,准入控制模块还可以访问正在创建或修改的对象的内容。

Kubernetes中的账户

Kubernetes的账户类型有两种:User Account和Service Account

User Account

理论基础

User Account是给使用人员用的,用于与API Server交互进行集群操作与管理。

使用HTTP 请求kubernetes API:

[root@clientvm ~]# kubectl proxy --port=8080
Starting to serve on 127.0.0.1:8080

[root@clientvm ~]# curl http://localhost:8080/api/v1/namespaces
{
  "kind": "NamespaceList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces",
    "resourceVersion": "3866057"
  },


[root@clientvm ~]# curl http://localhost:8080/apis/apps/v1/namespaces/kube-system/deployments
{
  "kind": "DeploymentList",
  "apiVersion": "apps/v1",
  "metadata": {
    "selfLink": "/apis/apps/v1/namespaces/kube-system/deployments",
    "resourceVersion": "3870674"
  },
  "items": [
    {
      "metadata": {
        "name": "coredns",

Kubernetes 使用身份认证插件利用客户端证书、持有者令牌(Bearer Token)、身份认证代理(Proxy) 或者 HTTP 基本认证机制来认证 API 请求的身份。

X509客户端证书认证

为了让普通用户能够通过认证并调用 API,需要执行一下几个步骤。
首先,该用户必须拥有 Kubernetes 集群签发的证书, 然后将该证书作为 API 调用的 Certificate 头或通过 kubectl 提供。
1) 创建私钥

[root@clientvm ~]# openssl genrsa -out user1.key 2048

2) 创建CSR

openssl req -new -key user1.key -out user1.csr -subj "/CN=user1/O=kubernetes"

注: 以下步骤为使用CA证书签名,如果无法访问CA证书,也可以替换为步骤3、4直接使用在集群中签名,任选其一

## SCP user1.csr到master节点
[root@clientvm ~]# scp user1.csr master:/etc/kubernetes/pki/

## 登录到master节点,签名证书
[root@master pki]# pwd
/etc/kubernetes/pki
[root@master pki]# openssl x509 -req -in user1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out user1.crt

## 将生成的crt证书 copy 回clientvm
[root@master pki]# scp user1.crt clientvm:/root/

3) 证书签名

[root@clientvm ~]# cat user1.csr | base64 | tr -d "\n"

替换入下文件中的request内容

[root@clientvm ~]# cat  user1-csr.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: user1
spec:
  groups:
  - system:authenticated
  request: NEED TO REPLACE
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth

4)签名,获取证书

[root@clientvm ~]# kubectl apply -f user1-csr.yaml
certificatesigningrequest.certificates.k8s.io/user1 created

[root@clientvm ~]# kubectl get csr
NAME    AGE   SIGNERNAME                            REQUESTOR          CONDITION
user1   18s   kubernetes.io/kube-apiserver-client   kubernetes-admin   Pending

[root@clientvm ~]# kubectl certificate approve user1
certificatesigningrequest.certificates.k8s.io/user1 approved
[root@clientvm ~]# kubectl get csr/user1 -o yaml
## 证书的内容使用 base64 编码,存放在字段 status.certificate

保存status.certificate内容到一个文件aaa,生成证书 crt

[root@clientvm ~]# cat aaa |base64 --decode >user1.crt

5) 添加user1到kubeconfig

[root@clientvm ~]# kubectl config set-credentials user1 --client-key=user1.key --client-certificate=user1.crt --embed-certs=true 
User "user1" set.
  1. 添加上下文
[root@clientvm ~]# kubectl config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin

[root@clientvm ~]# kubectl config set-context user1@kubernetes --cluster=kubernetes --user=user1
Context "user1@kubernetes" created.

7) 把上下文切换为user1

[root@clientvm ~]# kubectl config use-context user1@kubernetes
Switched to context "user1@kubernetes".


##此处报权限错误是因为只做了认证,还没有授权
[root@clientvm ~]# kubectl get pod
Error from server (Forbidden): pods is forbidden: User "user1" cannot list resource "pods" in API group "" in the namespace "default"

管理配置上下文

基本步骤

  1. 添加用户
kubectl config set-credentials -h
  1. 添加 cluster
kubectl config set-cluster -h
  1. 添加 context
kubectl config set-context
  1. 切换使用
[root@clientvm ~]# kubectl config current-context
kubernetes-admin@kubernetes

[root@clientvm ~]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".

[root@clientvm ~]# kubectl config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin
          user1@kubernetes              kubernetes   user1

Service Account

当你(自然人)访问集群时(例如,使用 kubectl),API 服务器将你的身份验证为 特定的用户帐户(当前这通常是 admin,除非你的集群管理员已经定制了你的集群配置)。 Pod 内的容器中的进程也可以与 api 服务器接触。 当它们进行身份验证时,它们被验证为特定的服务帐户(例如,default

服务账号通常由 API 服务器自动创建并通过 ServiceAccount 准入控制器 关联到集群中运行的 Pod 上。 相关Token会挂载到 Pod 中可预知的位置,允许集群内进程与 API 服务器通信。

当你创建 Pod 时,如果没有指定服务账户,Pod 会被指定给命名空间中的 default 服务账户。 也可以在Pod中添加serviceAccountName明确指定SA。

[root@clientvm ~]# kubectl get pod nginx2 -o yaml | grep -i serviceaccount
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
  serviceAccount: default
  serviceAccountName: default

创建SA:

[root@clientvm ~]# kubectl create serviceaccount -h
Create a service account with the specified name.

Aliases:
serviceaccount, sa

Examples:
  # Create a new service account named my-service-account
  kubectl create serviceaccount my-service-account

创建SA后,系统会自动创建一个token

[root@clientvm ~]# kubectl get sa,secret -n mytest
NAME                     SECRETS   AGE
serviceaccount/default   1         18d
serviceaccount/my-sa     1         15s

NAME                         TYPE                                  DATA   AGE
secret/default-token-64sch   kubernetes.io/service-account-token   3      18d
secret/my-sa-token-w6d7f     kubernetes.io/service-account-token   3      15s
[root@clientvm ~]# kubectl get serviceaccounts my-sa -n mytest  -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2020-12-16T05:24:27Z"
  name: my-sa
  namespace: mytest
  resourceVersion: "4060881"
  selfLink: /api/v1/namespaces/mytest/serviceaccounts/my-sa
  uid: 85bd0753-5ebf-4c5f-8046-5dbd4391f739
secrets:
- name: my-sa-token-w6d7f

从私有镜像仓库获取镜像
Option 1) 在Pod中引 ImagePullSecrets

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: myregistryke

Option 2)添加 docker-registry 类似的secret到default SA

kubectl create secret docker-registry myregistrykey --docker-server=DUMMY_SERVER \
          --docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'

RBAC授权

基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对 计算机或网络资源的访问的方法。

RBAC 鉴权机制使用 rbac.authorization.k8s.io API 组 来驱动鉴权决定,允许你通过 Kubernetes API 动态配置策略。

要启用 RBAC,在启动 API 服务器 时将 –authorization-mode 参数设置为一个逗号分隔的列表并确保其中包含 RBAC

RBAC API 声明了四种 Kubernetes 对象:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding。

Role 和 ClusterRole

RBAC 的 Role 或 ClusterRole 中包含一组代表相关权限的规则。 这些权限是纯粹累加的(不存在拒绝某操作的规则)

Role 总是用来在某个名字空间 内设置访问权限;在你创建 Role 时,你必须指定该 Role 所属的名字空间。
与之相对,ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和 ClusterRole)是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的, 不可两者兼具。

如果你希望在名字空间内定义角色,应该使用 Role; 如果你希望定义集群范围的角色,应该使用 ClusterRole。

role可包含的操作有:

"get", "list", "watch", "create", "update", "patch", "delete"

role常用可操作资源有:Pods, ConfigMaps, Deploments, Nodes, Secrets, Namespaces

核心组件角色

默认 ClusterRole默认 ClusterRoleBinding描述
cluster-adminsystem:masters允许超级用户在平台上的任何资源上执行所有操作。 当在 ClusterRoleBinding 中使用时,可以授权对集群中以及所有名字空间中的全部资源进行完全控制。 当在 RoleBinding 中使用时,可以授权控制 RoleBinding 所在名字空间中的所有资源,包括名字空间本身。
admin允许管理员访问权限,旨在使用 RoleBinding 在名字空间内执行授权。 如果在 RoleBinding 中使用,则可授予对名字空间中的大多数资源的读/写权限, 包括创建角色和角色绑定的能力。 但是它不允许对资源配额或者名字空间本身进行写操作。
edit允许对名字空间的大多数对象进行读/写操作。 它不允许查看或者修改角色或者角色绑定。 不过,此角色可以访问 Secret,以名字空间中任何 ServiceAccount 的身份运行 Pods, 所以可以用来了解名字空间内所有服务账号的 API 访问级别。

Role范例:

[root@clientvm ~]# kubectl create role -h
Usage:
  kubectl create role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename]
[--dry-run=server|client|none] [options]

Examples:
  # Create a Role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods
  kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods

  # Create a Role named "pod-reader" with ResourceName specified
  kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod

  # Create a Role named "foo" with API Group specified
  kubectl create role foo --verb=get,list,watch --resource=rs.extensions

  # Create a Role named "foo" with SubResource specified
  kubectl create role foo --verb=get,list,watch --resource=pods,pods/status
[root@clientvm ~]# cat role-example.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: mytest
  name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
[root@clientvm ~]# kubectl apply -f role-example.yaml
role.rbac.authorization.k8s.io/pod-reader created

ClusterRole范例

[root@clientvm ~]# kubectl create clusterrole -h
Usage:
  kubectl create clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename]
[--dry-run=server|client|none] [options]

Examples:
  # Create a ClusterRole named "pod-reader" that allows user to perform "get", "watch" and "list" on pods
  kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods

  # Create a ClusterRole named "pod-reader" with ResourceName specified
  kubectl create clusterrole pod-reader --verb=get --resource=pods --resource-name=readablepod
--resource-name=anotherpod

  # Create a ClusterRole named "foo" with API Group specified
  kubectl create clusterrole foo --verb=get,list,watch --resource=rs.extensions

  # Create a ClusterRole named "foo" with SubResource specified
  kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status

  # Create a ClusterRole name "foo" with NonResourceURL specified
  kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*

  # Create a ClusterRole name "monitoring" with AggregationRule specified
  kubectl create clusterrole monitoring --aggregation-rule="rbac.example.com/aggregate-to-monitoring=true"
[root@clientvm ~]# cat clusterrole-example.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  # 在 HTTP 层面,用来访问 Secret 对象的资源的名称为 "secrets"
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]
[root@clientvm ~]# kubectl apply -f clusterrole-example.yaml
clusterrole.rbac.authorization.k8s.io/secret-reader created
[root@clientvm ~]# kubectl get role -n mytest
NAME         CREATED AT
pod-reader   2020-12-16T04:41:56Z
[root@clientvm ~]# kubectl get clusterrole | grep secret
secret-reader                                                          2020-12-16T04:44:26Z

RoleBinding 和 ClusterRoleBinding

角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权。

一个 RoleBinding 可以引用同一的名字空间中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。

RoleBinding 范例

[root@clientvm ~]# kubectl create rolebinding -h
Usage:
  kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname]
[--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none] [options]

Examples:
  # Create a RoleBinding for user1, user2, and group1 using the admin ClusterRole
  kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1

将clusterrole admin 绑定到之前创建的user account user1

[root@clientvm ~]# kubectl create rolebinding admin-to-user1 --clusterrole=admin --user=user1
rolebinding.rbac.authorization.k8s.io/admin-to-user1 created

[root@clientvm ~]# kubectl --context=user1 get pod
NAME                     READY   STATUS      RESTARTS   AGE
nginx-taint              1/1     Running     0          37h
nginx2                   1/1     Running     0          4d20h

ClusterRoleBinding 范例

[root@clientvm ~]# kubectl create clusterrolebinding -h
Usage:
  kubectl create clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname]
[--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none] [options]

Examples:
  # Create a ClusterRoleBinding for user1, user2, and group1 using the cluster-admin ClusterRole
  kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1

准入控制(Admission Controllers)

英文:
https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#what-does-each-admission-controller-do
中文:
https://kubernetes.io/zh/docs/reference/access-authn-authz/admission-controllers/
启用额外的准入控制器:

[root@master manifests]# grep admission ./kube-apiserver.yaml
    - --enable-admission-plugins=NodeRestriction

关闭准入控制器:

 ## 添加如下参数
 --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...

默认启用的控制器:

NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota

网络策略

理论基础

如果你希望在 IP 地址或端口层面(OSI 第 3 层或第 4 层)控制网络流量, 则你可以考虑为集群中特定应用使用 Kubernetes 网络策略(NetworkPolicy)。 NetworkPolicy 是一种以应用为中心的结构,允许你设置如何允许 Pod 与网络上的各类网络“实体” 通信。

Pod 可以通信的 Pod 是通过如下三个标识符的组合来辩识的:

  1. 其他被允许的 Pods(例外:Pod 无法阻塞对自身的访问)
  2. 被允许的名字空间
  3. IP 组块(例外:与 Pod 运行所在的节点的通信总是被允许的, 无论 Pod 或节点的 IP 地址)

在定义基于 Pod 或名字空间的 NetworkPolicy 时,你会使用 选择算符 来设定哪些流量 可以进入或离开与该算符匹配的 Pod。 当基于 IP 的 NetworkPolicy 被创建时,我们基于 IP 组块(CIDR 范围) 来定义策略。
网络策略通过网络插件 来实现。要使用网络策略,你必须使用支持 NetworkPolicy 的网络解决方案。

语法说明

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
##1)对default NameSpace中包含标签role=db的Pod做控制
  policyTypes:
  - Ingress
  - Egress
##2)控制出入流量,未明确指定都是拒绝
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
##3)允许的网段,例外网段 
    - namespaceSelector:
        matchLabels:
          project: myproject
##4)允许的NameSpace
    - podSelector:
        matchLabels:
          role: frontend
##5)允许的Pod
    ports:
    - protocol: TCP
      port: 6379
##6) 定义被访问的端口
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978
##7)允许要控制的Pod访问哪个  "网段:端口" 的流量

注意From和To的行为

1)表示交集,and 运算

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
      podSelector:
        matchLabels:
          role: client
  ...

2)表示并集,or 运算

  ...
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          user: alice
    - podSelector:
        matchLabels:
          role: client
  ...

默认策略:拒绝所有进入流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress

默认策略:允许所有进入流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

范例1: 允许指定网段的入站流量

[root@clientvm ~]# cat deny-all-except.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-ingress-except
spec:
  podSelector:
    matchLabels:
      run: nginx1
  policyTypes:
  - Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 10.244.0.0/16
        except:
        - 10.244.102.0/24
    - ipBlock:
        cidr: 192.168.241.0/24
[root@clientvm ~]#
[root@clientvm ~]# kubectl get pod --show-labels -o wide
NAME             READY   STATUS    RESTARTS   AGE     IP               NODE                  NOMINATED NODE   READINESS GATES   LABELS
busybox          1/1     Running   0          5m23s   10.244.102.144   worker1.example.com   <none>           <none>            run=busybox
nginx1           1/1     Running   0          10h     10.244.71.195    worker2.example.com   <none>           <none>            run=nginx1
nginx2           1/1     Running   0          10h     10.244.71.196    worker2.example.com   <none>           <none>            run=nginx2
nginx3-default   1/1     Running   0          8h      10.244.102.133   worker1.example.com   <none>           <none>            run=nginx3-

[root@master ~]# ip a | grep 192
    inet 192.168.241.129/24 brd 192.168.241.255 scope global eth0
[root@master ~]# ping 10.244.71.195
PING 10.244.71.195 (10.244.71.195) 56(84) bytes of data.
64 bytes from 10.244.71.195: icmp_seq=1 ttl=63 time=0.484 ms
64 bytes from 10.244.71.195: icmp_seq=2 ttl=63 time=0.276 ms
64 bytes from 10.244.71.195: icmp_seq=3 ttl=63 time=0.217 ms
^C
--- 10.244.71.195 ping statistics ---
[root@clientvm ~]# kubectl run busybox --image=busybox --image-pull-policy=IfNotPresent -- sleep 10000
pod/busybox created
[root@clientvm ~]#
[root@clientvm ~]# kubectl get pod -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE                  NOMINATED NODE   READINESS GATES
busybox          1/1     Running   0          10s   10.244.102.144   worker1.example.com   <none>           <none>
nginx1           1/1     Running   0          10h   10.244.71.195    worker2.example.com   <none>           <none>
nginx2           1/1     Running   0          10h   10.244.71.196    worker2.example.com   <none>           <none>
nginx3-default   1/1     Running   0          8h    10.244.102.133   worker1.example.com   <none>           <none>

[root@clientvm ~]# kubectl exec busybox -it -- sh
/ # ping 10.244.71.195
PING 10.244.71.195 (10.244.71.195): 56 data bytes
^C
--- 10.244.71.195 ping statistics ---
5 packets transmitted, 0 packets received, 100% packet loss
/ # ping 10.244.71.196
PING 10.244.71.196 (10.244.71.196): 56 data bytes
64 bytes from 10.244.71.196: seq=0 ttl=62 time=0.547 ms
64 bytes from 10.244.71.196: seq=1 ttl=62 time=0.341 ms
^C
--- 10.244.71.196 ping statistics ---

范例2: 允许到指定端口的出站流量

目的:Pod Nginx1可以访问namespace内的Pod的80端口,不允许访问其他

[root@clientvm ~]# cat allow-egress-to-port.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-ingress-except
spec:
  podSelector:
    matchLabels:
      run: nginx1
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          app: myapp
    ports:
    - protocol: TCP
      port: 80

验证:

[root@clientvm ~]# kubectl get pod -o wide -n mytest
NAME      READY   STATUS    RESTARTS   AGE   IP              NODE                  NOMINATED NODE   READINESS GATES
nginxaa   1/1     Running   0          10m   10.244.71.200   worker2.example.com   <none>           <none>
[root@clientvm ~]# kubectl get pod -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE                  NOMINATED NODE   READINESS GATES
busybox          1/1     Running   0          33m   10.244.102.144   worker1.example.com   <none>           <none>
nginx1           1/1     Running   0          10h   10.244.71.195    worker2.example.com   <none>           <none>
[root@clientvm ~]# kubectl exec nginx1 -it -- bash
root@nginx1:/#
root@nginx1:/# curl 10.244.71.200
^C
root@nginx1:/# curl 10.244.71.195
AAAAAA
root@nginx1:/# exit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值