k8s十 | 一文讀懂基于角色的權(quán)限控制RBAC

?一洞渔、ServiceAccount

1. ServiceAccount 介紹

首先Kubernetes中賬戶區(qū)分為:User Accounts(用戶賬戶) 和 Service Accounts(服務(wù)賬戶) 兩種,它們的設(shè)計(jì)區(qū)別如下:

  • UserAccount是給kubernetes集群外部用戶使用的吧慢,例如運(yùn)維或者集群管理人員,使用kubectl命令時(shí)用的就是UserAccount賬戶引矩;UserAccount是全局性严里。在集群所有namespaces中,名稱具有唯一性伤靠,默認(rèn)情況下用戶為admin;
  • ServiceAccount是給運(yùn)行在Pod的程序使用的身份認(rèn)證啼染,Pod容器的進(jìn)程需要訪問API Server時(shí)用的就是ServiceAccount賬戶宴合;ServiceAccount僅局限它所在的namespace,每個(gè)namespace都會(huì)自動(dòng)創(chuàng)建一個(gè)default service account迹鹅;創(chuàng)建Pod時(shí)卦洽,如果沒有指定Service Account,Pod則會(huì)使用default Service Account斜棚。

2. 默認(rèn)Service Account

在上篇文章 k8s九 | 詳解配置對(duì)象ConfigMap與Secret最后kubernetes.io/service-account-token一節(jié)中我們已經(jīng)提到創(chuàng)建命名空間時(shí)會(huì)創(chuàng)建一個(gè)默認(rèn)的Service Account阀蒂,而ServiceAccout 創(chuàng)建時(shí)也會(huì)創(chuàng)建對(duì)應(yīng)的 Secret该窗,下面我們實(shí)際操作下。

創(chuàng)建命名空間

$ kubectl  create  ns  anmin
namespace/anmin created

查看命名空間的ServiceAccount

$ kubectl  get sa -n anmin
NAME      SECRETS   AGE
default   1         27s

查看ServiceAccount的Secret

$ kubectl  describe  sa  default   -n anmin
Name:                default
Namespace:           anmin
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-bskds
Tokens:              default-token-bskds
Events:              <none>
$ kubectl  get  secret -n anmin
NAME                  TYPE                                  DATA   AGE
default-token-bskds   kubernetes.io/service-account-token   3      75s

可以看到在創(chuàng)建名為“anmin”的命名空間后蚤霞,自動(dòng)創(chuàng)建了名為“default”的ServiceAccount酗失,并為“default”服務(wù)賬戶創(chuàng)建了對(duì)應(yīng)kubernetes.io/service-account-token類型的secret。

創(chuàng)建一個(gè)Pod

apiVersion: v1
kind: Pod
metadata:
  name: testpod
  namespace: anmin
spec:
  containers:
  - name: testpod
    image: busybox
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']

查看Pod的Service Account信息

$ kubectl  create -f anmin.yaml 
pod/testpod created
$ kubectl  describe pod  testpod  -n anmin
..........
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-bskds (ro)
..........
Volumes:
  default-token-bskds:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-bskds
    Optional:    false
.........

在不指定ServiceAccount的情況下昧绣,當(dāng)前 namespace 下面的 Pod 會(huì)默認(rèn)使用 “default” 這個(gè) ServiceAccount规肴,對(duì)應(yīng)的 Secret 會(huì)自動(dòng)掛載到 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount/ 目錄中,我們可以在 Pod 里面獲取到用于身份認(rèn)證的信息夜畴。

$ kubectl  exec -it testpod -n anmin -- /bin/sh
/ # ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt     namespace  token

3. 使用自定義的ServiceAccount

創(chuàng)建一個(gè)Service Account

$ kubectl  create sa anmin -n anmin
serviceaccount/anmin created
$ kubectl  get sa -n anmin
NAME      SECRETS   AGE
anmin     1         20s
default   1         31m
$ kubectl   get secret -n anmin
NAME                  TYPE                                  DATA   AGE
anmin-token-nkb8b     kubernetes.io/service-account-token   3      28s
default-token-bskds   kubernetes.io/service-account-token   3      31m

Pod使用剛創(chuàng)建的ServiceAccount

apiVersion: v1
kind: Pod
metadata:
  name: testpod
  namespace: anmin
spec:
  containers:
  - name: testpod
    image: busybox
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
  serviceAccountName: anmin

更新Pod

$ kubectl   apply -f anmin.yaml 
pod/testpod created
$ kubectl  describe  pod  testpod -n anmin
.........
   Mounts:
     /var/run/secrets/kubernetes.io/serviceaccount from anmin-token-nkb8b (ro)
Conditions:
 Type              Status
 Initialized       True 
 Ready             True 
 ContainersReady   True 
 PodScheduled      True 
Volumes:
 anmin-token-nkb8b:
   Type:        Secret (a volume populated by a Secret)
   SecretName:  anmin-token-nkb8b
   Optional:    false
   ............

可以看到更新后的Pod已經(jīng)使用了新創(chuàng)建的ServiceAccount服務(wù)賬戶拖刃。

4. ServiceAccount中添加Image pull secrets

我們也可以在Service Account中設(shè)置imagePullSecrets,然后就會(huì)自動(dòng)為使用該 SA 的 Pod 注入 imagePullSecrets 信息贪绘。

創(chuàng)建kubernetes.io/dockerconfigjson類型的私有倉庫鏡像Secret

$ kubectl create secret docker-registry harbor --docker-server=http://192.168.166.229  --docker-username=admin   --docker-password=1234567  --docker-email=test@163.com   -n anmin
2secret/harbor created

將鏡像倉庫的Secret添加到ServiceAccount

$ kubectl  edit sa  anmin  -n anmin
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2020-06-16T16:09:54Z"
  name: anmin
  namespace: anmin
  resourceVersion: "37509823"
  selfLink: /api/v1/namespaces/anmin/serviceaccounts/anmin
  uid: c6bec7bb-808d-459f-86c8-6c78b48cb3ab
secrets:
- name: anmin-token-nkb8b
imagePullSecrets:
- name: harbor

查看ServiceAccount中Image pull secrets字段信息

$ kubectl  describe sa  anmin -n  anmin 
Name:                anmin
Namespace:           anmin
Labels:              <none>
Annotations:         <none>
Image pull secrets:  harbor
Mountable secrets:   anmin-token-nkb8b
Tokens:              anmin-token-nkb8b
Events:              <none>

使用ServiceAccount拉取私有鏡像部署Pod

apiVersion: v1
kind: Pod
metadata:
  name: anmin2
  namespace: anmin
spec:
  containers:
  - name: anmin2
    image: 192.168.166.229/1an/node-exporter:latest
  serviceAccountName: anmin

更新Pod并查看狀態(tài)

$ kubectl  apply -f harborsecret.yaml 
pod/anmin2 created
$ kubectl  get pod -n anmin
NAME         READY   STATUS             RESTARTS   AGE
anmin2       1/1     Running            0          20s
$ kubectl describe pod  anmin2 -n anmin
......
Volumes:
  anmin-token-nkb8b:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  anmin-token-nkb8b
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From                 Message
  ----    ------     ----  ----                 -------
  Normal  Pulling    8h    kubelet, k8s-node01  Pulling image "192.168.166.229/1an/node-exporter:latest"
  Normal  Pulled     8h    kubelet, k8s-node01  Successfully pulled image "192.168.166.229/1an/node-exporter:latest"

可以看到Pod已經(jīng)成功從鏡像倉庫拉取鏡像并正常運(yùn)行兑牡。

二、RBAC

1. RBAC介紹

在Kubernetes 中所有資源對(duì)象都是通過 API 對(duì)象進(jìn)行操作兔簇, 它們保存在 Etcd 里发绢。而對(duì)Etcd的操作我們需要通過訪問 kube-apiserver來實(shí)現(xiàn)硬耍,上面的Service Account其實(shí)就是APIServer的認(rèn)證過程垄琐,而授權(quán)的機(jī)制則是通過RBAC:基于角色的訪問控制實(shí)現(xiàn)的。

Role + RoleBinding + ServiceAccount 的權(quán)限分配方式是要重點(diǎn)掌握的內(nèi)容经柴。

RBAC的三個(gè)基本概念:

  1. Role:角色狸窘,其實(shí)是一組規(guī)則,定義了一組對(duì) Kubernetes API 對(duì)象的操作權(quán)限坯认;
  2. Subject:被作用者翻擒,既可以是“人”,也可以是“機(jī)器”牛哺,也就是在 Kubernetes 里定義的“用戶”陋气;
  3. RoleBinding:定義了“被作用者”和“角色”的綁定關(guān)系。

2. Role與RoleBinding

現(xiàn)在我們通過實(shí)際操作來理解RBAC的工作機(jī)制
創(chuàng)建一個(gè)Service Account

$ kubectl  create sa  zhanmin-sa  -n kube-system
serviceaccount/zhanmin created

定義一個(gè)Role對(duì)象 zhanmin-sa-role.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: zhanmin-sa-role
  namespace: kube-system
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

在上面的文件我們定義了被作用的命名空間為:kube-system引润,其中的rules 字段巩趁,就是它所定義的權(quán)限規(guī)則。其中規(guī)則定義的角色對(duì)Pod沒有創(chuàng)建淳附、刪除议慰、更新的權(quán)限。

其中的“被作用者”我們則是通過RoleBinding 對(duì)象來指定奴曙。

定義Rolebinding對(duì)象 zhanmin-sa-rolebinding.yaml

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: zhanmin-sa-rolebinding
  namespace: kube-system
subjects:
- kind: ServiceAccount
  name: zhanmin-sa
  namespace: kube-system
roleRef:
  kind: Role
  name: zhanmin-sa-role
  apiGroup: rbac.authorization.k8s.io

subjects 字段别凹,即“被作用者”。它的類型是 User洽糟,即 Kubernetes 里的用戶炉菲,也就是上文中的Service Account堕战,這里我們定義被作用者用戶為“zhanmin-sa”。

roleRef則是定義:RoleBinding 對(duì)象可以直接通過名字拍霜,來引用我們前面定義的 Role 對(duì)象践啄,也就是“zhanmin-sa-role”,從而定義了“被作用者(Subject)”和“角色(Role)”之間的綁定關(guān)系沉御。

所以Pod使用名為“zhanmin-sa”的ServiceAccount訪問API Server時(shí)只能夠做對(duì)Pod做get", "watch", "list"操作屿讽。這是因?yàn)椤皕hanmin-sa” 這個(gè) ServiceAccount 的權(quán)限,已經(jīng)被我們綁定了 Role 做了限制吠裆。

注意:Role 和 RoleBinding 對(duì)象都是 Namespaced 對(duì)象(Namespaced Object)伐谈,它們對(duì)權(quán)限的限制規(guī)則僅在它們自己的 Namespace 內(nèi)有效,roleRef 也只能引用當(dāng)前 Namespace 里的 Role 對(duì)象试疙。

下面創(chuàng)建這些對(duì)象

$ kubectl   create -f zhanmin-sa-role.yaml 
role.rbac.authorization.k8s.io/zhanmin-sa-role created
$ kubectl  create -f  zhanmin-sa-rolebinding.yaml 
rolebinding.rbac.authorization.k8s.io/zhanmin-sa-rolebinding created

現(xiàn)在可以去之前部署的kubernetes-dashboard上驗(yàn)證權(quán)限
獲取當(dāng)前Service Account的Secret信息

$ kubectl  get secret  -n kube-system
zhanmin-sa-token-x6gxs                           kubernetes.io/service-account-token   3      136m
$ kubectl   get secret   zhanmin-sa-token-x6gxs  -o jsonpath={.data.token} -n kube-system |base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6InJCZFhYLTVRc2E4STlGVVN0VzEwWlc2M1VGMVF0ZDZFaFdJQlc3V2RLMzAifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VeXN

現(xiàn)在可以去之前部署的kubernetes-dashboard上驗(yàn)證權(quán)限
命名空間修改為kube-system诵棵,因?yàn)樯厦嫖覀円呀?jīng)說了Service Account只對(duì)當(dāng)前的namespace有效。


在這里插入圖片描述

在這里插入圖片描述

可以看到祝旷,權(quán)限是符合我們上面的定義履澳,只可以查看Pod和Deployments對(duì)象,查看其他資源比如SVC顯示是沒有數(shù)據(jù)的怀跛。后面我們可以根據(jù)自己的需求去查詢API對(duì)象修改相應(yīng)的權(quán)限規(guī)則距贷。

3. ClusterRole 和 ClusterRoleBinding

上面的Role和RoleBinding只可以在他們自己的命名空間中有效,如果我們需要一個(gè)具有全部命名空間或者對(duì)節(jié)點(diǎn)有權(quán)限的角色時(shí)吻谋,就需要使用ClusterRole 和 ClusterRoleBinding 對(duì)象來做授權(quán)了忠蝗。

ClusterRole 和 ClusterRoleBinding 這兩個(gè) API 對(duì)象的用法跟 Role 和 RoleBinding 幾乎完全一樣。不一樣的是漓拾,它們的定義里阁最,沒有了 Namespace 字段,權(quán)限可以作用于整個(gè)集群骇两。

創(chuàng)建ClusterRole集群角色 clusterrole.yaml

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: clusterrole-anmin
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

含義為:名為“clusterrole-anmin”的集群角色可以對(duì)集群所有命名空間的Pod進(jìn)行“GET速种、Watch、List” 操作低千。

在Role 或者 ClusterRole 里面配阵,如果要賦予用戶 example-user 所有權(quán)限,那你就可以給它指定一個(gè) verbs 字段的全集栋操,如下所示:

verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

創(chuàng)建 ClusterRoleBinding集群角色綁定 ClusterRoleBinding.yaml

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-clusterrolebinding
subjects:
- kind: User
  name: user-anmin
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: clusterrole-anmin
  apiGroup: rbac.authorization.k8s.io

含義為: subjects字段定義被作用者用戶為“user-anmin”闸餐,roleRef字段定義:綁定名為“clusterrole-anmin”集群角色。

在 Kubernetes 中已經(jīng)內(nèi)置了很多個(gè)為系統(tǒng)保留的 ClusterRole矾芙,它們的名字都以 system: 開頭舍沙。你可以通過 kubectl get clusterroles查看到它們。

查看集群角色

$ kubectl get clusterroles 
NAME                                                                   AGE
admin                                                                  242d
calico-kube-controllers                                                211d
calico-node                                                            211d
cluster-admin                                                          242d
cluster-regular                                                        217d
edit                                                                   242d
......

查看角色的權(quán)限

$ kubectl describe clusterrole edit 
Name:         edit
Labels:       kubernetes.io/bootstrapping=rbac-defaults
              rbac.authorization.k8s.io/aggregate-to-admin=true
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources                                Non-Resource URLs  Resource Names  Verbs
  ---------                                -----------------  --------------  -----
  configmaps                               []                 []              [create delete deletecollection patch update get list watch]
  endpoints                                []                 []              [create delete deletecollection patch update get list watch]
  persistentvolumeclaims                   []                 []              [create delete deletecollection patch update get list watch]
  pods                                     []                 []              [create delete deletecollection patch update get list watch]
  replicationcontrollers/scale             []                 []              [create delete deletecollection patch update get list watch]
......

4. Group用戶組

Kubernetes 還擁有“用戶組”(Group)的概念剔宪,也就是一組“用戶”的意思拂铡。如果你為 Kubernetes 配置了外部認(rèn)證服務(wù)的話壹无,這個(gè)“用戶組”的概念就會(huì)由外部認(rèn)證服務(wù)提供。

ServiceAccount感帅,在 Kubernetes 里對(duì)應(yīng)的“用戶”的名字是:

system:serviceaccount:<Namespace名字>:<ServiceAccount名字>

對(duì)應(yīng)的內(nèi)置“用戶組”的名字斗锭,就是:

system:serviceaccounts:<Namespace名字>

比如,現(xiàn)在我們可以在 RoleBinding 里定義如下的 subjects:

subjects:
- kind: Group
  name: system:serviceaccounts
  apiGroup: rbac.authorization.k8s.io

這就意味著這個(gè) Role 的權(quán)限規(guī)則失球,作用于 mynamespace 里的所有 ServiceAccount岖是。這就用到了“用戶組”的概念。而下面這個(gè)例子:

subjects:
- kind: Group
  name: system:serviceaccounts
  apiGroup: rbac.authorization.k8s.io

就意味著這個(gè) Role 的權(quán)限規(guī)則实苞,作用于整個(gè)系統(tǒng)里的所有 ServiceAccount豺撑。

總結(jié):通過上面的實(shí)踐,我們了解了在kubernetes中用戶分為User Accounts和 Service Accounts黔牵,在我們平常的使用中會(huì)經(jīng)常使用ServiceAccount聪轿。而對(duì)于權(quán)限的控制,我們需要先創(chuàng)建角色(Role)猾浦,其實(shí)就是一組權(quán)限規(guī)則列表陆错。然后我們分配這些權(quán)限的方式,就是通過創(chuàng)建 RoleBinding 對(duì)象金赦,將被作用者(subject)Service Account和權(quán)限列表Role進(jìn)行綁定音瓷,也就是Role + RoleBinding + ServiceAccount來實(shí)現(xiàn)。另外ClusterRole 和 ClusterRoleBinding素邪,則是 Kubernetes 集群級(jí)別的 Role 和 RoleBinding外莲,它們的作用范圍不受 Namespace 限制猪半。

參考資料:

https://time.geekbang.org/column/article/42154
https://www.qikqiak.com/k8s-book/docs/30.RBAC.html


關(guān)注公眾號(hào)回復(fù)【k8s】獲取視頻教程及更多資料:


運(yùn)維技術(shù)社
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兔朦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子磨确,更是在濱河造成了極大的恐慌沽甥,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乏奥,死亡現(xiàn)場離奇詭異摆舟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)邓了,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門恨诱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骗炉,你說我怎么就攤上這事照宝。” “怎么了句葵?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵厕鹃,是天一觀的道長兢仰。 經(jīng)常有香客問我,道長剂碴,這世上最難降的妖魔是什么把将? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮忆矛,結(jié)果婚禮上察蹲,老公的妹妹穿的比我還像新娘。我一直安慰自己催训,他們只是感情好递览,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞳腌,像睡著了一般绞铃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嫂侍,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天儿捧,我揣著相機(jī)與錄音,去河邊找鬼挑宠。 笑死菲盾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的各淀。 我是一名探鬼主播懒鉴,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碎浇!你這毒婦竟也來了临谱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤奴璃,失蹤者是張志新(化名)和其女友劉穎悉默,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苟穆,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抄课,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雳旅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跟磨。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖攒盈,靈堂內(nèi)的尸體忽然破棺而出抵拘,到底是詐尸還是另有隱情,我是刑警寧澤沦童,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布仑濒,位于F島的核電站叹话,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏墩瞳。R本人自食惡果不足惜驼壶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喉酌。 院中可真熱鬧热凹,春花似錦、人聲如沸泪电。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽相速。三九已至碟渺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間突诬,已是汗流浹背苫拍。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旺隙,地道東北人绒极。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像蔬捷,于是被迫代替她去往敵國和親垄提。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355