kubeadm集群更改证书

Note: 本文基于使用kubeadm搭建的kubernetes集群进行讲解


第一步:获取证书签发信息

  • 方式一:通过原有证书进行获取相关信息

    • 获取apiserver签发信息

      $ openssl x509 -noout -text -in /etc/kubernetes/pki/apiserver.crt
      ......
      X509v3 extensions:
          X509v3 Key Usage: critical
              Digital Signature, Key Encipherment
          X509v3 Extended Key Usage:
              TLS Web Server Authentication
          X509v3 Subject Alternative Name:
              DNS:localhost, DNS:node1, DNS:node2, DNS:node3, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc,   DNS:kubernetes.default.svc.cluster.local, IP Address:127.0.0.1, IP Address:10.96.0.1, IP Address:192.168.12.10, IP   Address:192.168.12.11, IP Address:192.168.12.12, IP Address:192.168.12.13
      ......
      
    • 从上面输出信息可知签发的DNS和IP详情

      DNS.1 = localhost
      # 各 master 节点 nodeName
      DNS.2 = node1
      DNS.3 = node2
      DNS.4 = node3
      # kubenertes svc 地址
      DNS.5 = kubernetes
      DNS.6 = kubernetes.default
      DNS.7 = kubernetes.default.svc
      # 带 dns domain 的 kubenertes svc 地址
      DNS.8 = kubernetes.default.svc.cluster.local
      IP.6 = 127.0.0.1
      # kubenertes svc 的 clusterip
      IP.5 = 10.96.0.1
      # api-server VIP 地址
      IP.4 = 192.168.12.10
      # 各 master 节点 IP
      IP.1 = 192.168.12.11
      IP.2 = 192.168.12.12
      IP.3 = 192.168.12.13
      
  • 方式二:自行统计各项信息

    • 在创建证书之前需要获取到以下信息,在签发证书的时候会用到它:

      • 各master节点IP
      • 各master节点nodeName
      • 如果有设置apiserver负载均衡则需要VIP,否则请忽略
      • kubernetes集群dns domain
      • kubenertes.default.svc的clusterip
    • 本文以下面集群信息为例:

      • 节点信息:

        nodeName ip relo
        slb 192.168.12.10 slb
        node1 192.168.12.11 master
        node2 192.168.12.12 master
        node3 192.168.12.13 master
        node4 192.168.12.14 worker
        node5 192.168.12.15 worker
      • 获取kubernetes dns domain:

        # CoreDNS 查看方法
        $ kubectl get cm -n kube-system coredns -o yaml | grep kubernetes
        kubernetes cluster.local in-addr.arpa ip6.arpa {
        # 由以上输出可知dns domain为 cluster.local
        
        # kube-dns 查看方法
        $ kubectl get deployment -n kube-system kube-dns -o yaml | grep domain
        - --domain=cluster.local.
        # 由以上输出可知dns domain为 cluster.local
        
      • kubernetes apiserver clusterip

        $ kubectl get svc kubernetes -n default
        NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
        kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   280d
        # 由结果可知apiserver clusterip
        

同理获取etcd集群证书签发的DNS和IP详情,默认etcd证书路径为/etc/kubernetes/pki/etcd

第二步:创建证书

Note: 我们只需要在一个节点上进行证书生成,生成的证书分发到其他节点即可


  • 创建CA服务端证书签名请求配置文件openssl.conf,内容如下,注意替换alt_names_clusteralt_names_etcd域中的值

    [ req ]
    default_bits = 2048
    default_md = sha256
    distinguished_name = req_distinguished_name
    
    [req_distinguished_name]
    
    [ v3_ca ]
    basicConstraints = critical, CA:TRUE
    keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign
    
    [ v3_req_server ]
    basicConstraints = CA:FALSE
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth
    
    [ v3_req_client ]
    basicConstraints = CA:FALSE
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = clientAuth
    
    [ v3_req_apiserver ]
    basicConstraints = CA:FALSE
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName = @alt_names_cluster
    
    [ v3_req_etcd ]
    basicConstraints = CA:FALSE
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth, clientAuth
    subjectAltName = @alt_names_etcd
    
    [ alt_names_cluster ]
    DNS.1 = localhost
    DNS.2 = node1
    DNS.3 = node2
    DNS.4 = node3
    DNS.5 = kubernetes
    DNS.6 = kubernetes.default
    DNS.7 = kubernetes.default.svc
    DNS.8 = kubernetes.default.svc.cluster.local
    IP.1 = 127.0.0.1
    IP.2 = 10.96.0.1
    IP.3 = 192.168.12.10
    IP.4 = 192.168.12.11
    IP.5 = 192.168.12.12
    IP.6 = 192.168.12.13
    
    [ alt_names_etcd ]
    DNS.1 = localhost
    DNS.2 = node1
    DNS.3 = node2
    DNS.4 = node3
    IP.1 = 127.0.0.1
    IP.2 = 0:0:0:0:0:0:0:1
    IP.3 = 192.168.12.11
    IP.4 = 192.168.12.12
    IP.5 = 192.168.12.13
    
  • 创建集群 key 与 CA

    • 将要创建的 CA

      路径 Common Name 描述
      ca.crt,key kubernetes Kubernetes general CA
      etcd/ca.crt,key kubernetes For all etcd-related functions
      front-proxy-ca.crt,key kubernetes For the front-end proxy
    • 要注意 CA 中 CN(Common Name) 与 O(Organization) 等内容是会影响Kubernetes组件认证的

      • CA (Certificate Authority) 是自签名的根证书,用来签名后续创建的其它证书
      • CN (Common Name), apiserver 会从证书中提取该字段作为请求的用户名 (User Name)
      • O (Organization), apiserver 会从证书中提取该字段作为请求用户所属的组 (Group)

    一般CA根证书有效期为10年,若举例过期时间还长,可跳过本节操作,命令中的3650为3650天,即证书有效期。

    • kubernetes-ca

      openssl genrsa -out ca.key 2048
      openssl req -x509 -new -nodes -key ca.key \
        -subj "/CN=kubernetes" -config openssl.conf \
        -extensions v3_ca -out ca.crt -days 3560
      
    • etcd-ca

      mkdir -p etcd
      openssl genrsa -out etcd/ca.key 2048
      openssl req -x509 -new -nodes -key etcd/ca.key \
        -subj "/CN=kubernetes" -config openssl.conf \
        -extensions v3_ca -out etcd/ca.crt -days 3560
      
    • front-proxy-ca

      openssl genrsa -out front-proxy-ca.key 2048
      openssl req -x509 -new -nodes -key front-proxy-ca.key \
        -subj "/CN=kubernetes" -config openssl.conf \
        -extensions v3_ca -out front-proxy-ca.crt -days 3560
      
  • 创建 Certificates

    • 将要创建的 Certificates
      Name Key Certificates Common Name Organization
      etcd/server etcd/server.key etcd/server.crt master
      etcd/peer etcd/peer.key etcd/peer.crt master
      etcd/healthcheck-client etcd/healthcheck-client.key etcd/healthcheck-client.crt kube-etcd-healthcheck-client system:masters
      apiserver-etcd-client apiserver-etcd-client.key apiserver-etcd-client.crt kube-apiserver-etcd-client system:masters
      apiserver apiserver.key apiserver.crt kube-apiserver
      apiserver-kubelet-client apiserver-kubelet-client.key apiserver-kubelet-client.crt kube-apiserver-kubelet-client system:masters
      front-proxy-client front-proxy-client.key front-proxy-client.crt front-proxy-client
      kube-scheduler kube-scheduler.key kube-scheduler.crt system:kube-scheduler
      sa(kube-controller-manager) sa.key(sa.pub) kube-controller-manager.crt system:kube-controller-manager
      admin(kubectl) admin.key admin.crt kubernetes-admin system:masters
      kubelet kubelet.key kubelet.crt system:node:master system:nodes

mkdir etcd
cp /etc/kubernetes/pki/etcd/*.key etcd/
cp /etc/kubernetes/pki/etcd/ca.crt etcd/

  • etcd/server

    ~~openssl genrsa -out etcd/server.key 2048~~
    openssl req -new -key etcd/server.key \
      -subj "/CN=master" -out etcd/server.csr
    openssl x509 -in etcd/server.csr -req -CA etcd/ca.crt \
      -CAkey etcd/ca.key -CAcreateserial -extensions v3_req_etcd \
      -extfile openssl.conf -out etcd/server.crt -days 3560
    
  • etcd/peer

    ~~openssl genrsa -out etcd/peer.key 2048~~
    openssl req -new -key etcd/peer.key \
      -subj "/CN=master" -out etcd/peer.csr
    openssl x509 -in etcd/peer.csr -req -CA etcd/ca.crt \
      -CAkey etcd/ca.key -CAcreateserial -extensions v3_req_etcd \
      -extfile openssl.conf -out etcd/peer.crt -days 3560
    
  • etcd/healthcheck-client

    ~~openssl genrsa -out etcd/healthcheck-client.key 2048~~
    openssl req -new -key etcd/healthcheck-client.key \
      -subj "/CN=kube-etcd-healthcheck-client/O=system:masters" \
      -out etcd/healthcheck-client.csr
    openssl x509 -in etcd/healthcheck-client.csr -req -CA etcd/ca.crt \
      -CAkey etcd/ca.key -CAcreateserial -extensions v3_req_etcd \
      -extfile openssl.conf -out etcd/healthcheck-client.crt -days 3560
    

cp /etc/kubernetes/pki/*.key .
cp /etc/kubernetes/pki/ca.crt .
cp /etc/kubernetes/pki/front-proxy-ca.crt .

  • apiserver-etcd-client

    ~~openssl genrsa -out apiserver-etcd-client.key 2048~~
    openssl req -new -key apiserver-etcd-client.key \
      -subj "/CN=kube-apiserver-etcd-client/O=system:masters" \
      -out apiserver-etcd-client.csr
    openssl x509 -in apiserver-etcd-client.csr -req -CA etcd/ca.crt \
      -CAkey etcd/ca.key -CAcreateserial -extensions v3_req_etcd \
      -extfile openssl.conf -out apiserver-etcd-client.crt -days 3560
    
  • apiserver

    ~~openssl genrsa -out apiserver.key 2048~~
    openssl req -new -key apiserver.key \
      -subj "/CN=kube-apiserver" -config openssl.conf \
      -out apiserver.csr
    openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key \
      -CAcreateserial -extensions v3_req_apiserver \
      -extfile openssl.conf -out apiserver.crt -days 3560
    
  • apiserver-kubelet-client

    ~~openssl genrsa -out apiserver-kubelet-client.key 2048~~
    openssl req -new -key apiserver-kubelet-client.key \
      -subj "/CN=kube-apiserver-kubelet-client/O=system:masters" \
      -out apiserver-kubelet-client.csr
    openssl x509 -req -in apiserver-kubelet-client.csr -CA ca.crt -CAkey ca.key \
      -CAcreateserial -extensions v3_req_client \
      -extfile openssl.conf -out apiserver-kubelet-client.crt -days 3560
    
  • front-proxy-client

    ~~openssl genrsa -out front-proxy-client.key 2048~~
    openssl req -new -key front-proxy-client.key \
      -subj "/CN=front-proxy-client" \
      -out front-proxy-client.csr
    openssl x509 -req -in front-proxy-client.csr -CA front-proxy-ca.crt -CAkey front-proxy-ca.key \
      -CAcreateserial -extensions v3_req_client \
      -extfile openssl.conf -out front-proxy-client.crt -days 3560
    
  • kube-scheduler

    openssl genrsa -out kube-scheduler.key 2048
    openssl req -new -key kube-scheduler.key \
      -subj "/CN=system:kube-scheduler" \
      -out kube-scheduler.csr
    openssl x509 -req -in kube-scheduler.csr -CA ca.crt -CAkey ca.key \
      -CAcreateserial -extensions v3_req_client \
      -extfile openssl.conf -out kube-scheduler.crt -days 3560
    

cp /etc/kubernetes/pki/sa.pub .

  • sa(kube-controller-manager)

    ~~openssl genrsa -out sa.key 2048~~
    ~~openssl rsa -in sa.key -pubout -out sa.pub~~
    openssl req -new -key sa.key \
      -subj "/CN=system:kube-controller-manager" \
      -out kube-controller-manager.csr
    openssl x509 -req -in kube-controller-manager.csr -CA ca.crt -CAkey ca.key \
      -CAcreateserial -extensions v3_req_client \
      -extfile openssl.conf -out kube-controller-manager.crt -days 3560
    
  • admin(kubectl)

    openssl genrsa -out admin.key 2048
    openssl req -new -key admin.key \
      -subj "/CN=kubernetes-admin/O=system:masters" \
      -out admin.csr
    openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key \
      -CAcreateserial -extensions v3_req_client \
      -extfile openssl.conf -out admin.crt -days 3560 
    
  • kubelet

    openssl genrsa -out kubelet.key 2048
    # 此处为 master 节点 nodeName,每个 master 生成对应的证书
    openssl req -new -key kubelet.key \
      -subj "/CN=system:node:node1/O=system:nodes" \
      -out kubelet.csr
    openssl x509 -req -CA ca.crt -CAkey ca.key \
      -CAcreateserial -extensions v3_req_client \
      -extfile openssl.conf -days 3560 -in kubelet.csr -out kubelet.crt
    

第三步:生成kubernetes各组件配置文件并应用

  • 所要生成的配置文件列表

    配置文件名称 组件证书文件名称 组件秘钥文件名称 根证书文件名称
    admin.conf(kubectl) admin.crt admin.key ca.crt
    kubelet.conf kubelet.crt kubelet.key ca.crt
    scheduler.conf kube-scheduler.crt kube-scheduler.key ca.crt
    controller-manager.conf kube-controller-manager.crt sa.key ca.crt
    • 操作前请先备份原有配置文件
    • 除了kubelet.conf文件需注意配置为对应节点的nodeName,其余配置文件可通用
    • 以下操作请先在一台 master 节点上操作确认没有问题后再进行配置其他节点
    • –certificate-authority:指定根证书
    • –client-certificate、–client-key:指定组件证书及秘钥
    • –embed-certs=true:将组件证书内容嵌入到生成的配置文件中(不加时,写入的是证书文件路径)
  • admin.conf(kubectl)

    KUBE_APISERVER="https://192.168.12.10:6443"
    CLUSTER_NAME="kubernetes"
    KUBE_USER="kubernetes-admin"
    KUBE_CERT="admin"
    KUBE_CONFIG="admin.conf"
    
    # 设置集群参数
    kubectl config set-cluster ${CLUSTER_NAME} \
      --certificate-authority=ca.crt \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置客户端认证参数
    kubectl config set-credentials ${KUBE_USER} \
      --client-certificate=${KUBE_CERT}.crt \
      --client-key=${KUBE_CERT}.key \
      --embed-certs=true \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置上下文参数
    kubectl config set-context ${KUBE_USER}@${CLUSTER_NAME} \
      --cluster=${CLUSTER_NAME} \
      --user=${KUBE_USER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置当前使用的上下文
    kubectl config use-context ${KUBE_USER}@${CLUSTER_NAME} --kubeconfig=${KUBE_CONFIG}
    
    # 查看生成的配置文件
    kubectl config view --kubeconfig=${KUBE_CONFIG}
    

cp /etc/kubernetes/kubelet.conf .

  • kubelet.conf(注意配置对应的nodeName)

    KUBE_APISERVER="https://192.168.12.10:6443"
    CLUSTER_NAME="kubernetes"
    # 此处为 master 节点 nodeName,每个 master 生成对应的 kubelet.conf
    KUBE_USER="system:node1:master"
    KUBE_CERT="kubelet"
    KUBE_CONFIG="kubelet.conf"
    
    # 设置集群参数
    kubectl config set-cluster ${CLUSTER_NAME} \
      --certificate-authority=ca.crt \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置客户端认证参数
    kubectl config set-credentials ${KUBE_USER} \
      --client-certificate=${KUBE_CERT}.crt \
      --client-key=kubelet.key \
      --embed-certs=true \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置上下文参数
    kubectl config set-context ${KUBE_USER}@${CLUSTER_NAME} \
      --cluster=${CLUSTER_NAME} \
      --user=${KUBE_USER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置当前使用的上下文
    kubectl config use-context ${KUBE_USER}@${CLUSTER_NAME} --kubeconfig=${KUBE_CONFIG}
    
    # 查看生成的配置文件
    kubectl config view --kubeconfig=${KUBE_CONFIG}
    
  • scheduler.conf

    KUBE_APISERVER="https://192.168.12.10:6443"
    CLUSTER_NAME="kubernetes"
    KUBE_USER="system:kube-scheduler"
    KUBE_CERT="kube-scheduler"
    KUBE_CONFIG="scheduler.conf"
    
    # 设置集群参数
    kubectl config set-cluster ${CLUSTER_NAME} \
      --certificate-authority=ca.crt \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置客户端认证参数
    kubectl config set-credentials ${KUBE_USER} \
      --client-certificate=${KUBE_CERT}.crt \
      --client-key=${KUBE_CERT}.key \
      --embed-certs=true \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置上下文参数
    kubectl config set-context ${KUBE_USER}@${CLUSTER_NAME} \
      --cluster=${CLUSTER_NAME} \
      --user=${KUBE_USER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置当前使用的上下文
    kubectl config use-context ${KUBE_USER}@${CLUSTER_NAME} --kubeconfig=${KUBE_CONFIG}
    
    # 查看生成的配置文件
    kubectl config view --kubeconfig=${KUBE_CONFIG}
    
  • controller-manager.conf

    KUBE_APISERVER="https://192.168.12.10:6443"
    CLUSTER_NAME="kubernetes"
    KUBE_USER="system:kube-controller-manager"
    KUBE_CERT="kube-controller-manager"
    KUBE_CONFIG="controller-manager.conf"
    
    # 设置集群参数
    kubectl config set-cluster ${CLUSTER_NAME} \
      --certificate-authority=ca.crt \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置客户端认证参数
    kubectl config set-credentials ${KUBE_USER} \
      --client-certificate=${KUBE_CERT}.crt \
      --client-key=sa.key \
      --embed-certs=true \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置上下文参数
    kubectl config set-context ${KUBE_USER}@${CLUSTER_NAME} \
      --cluster=${CLUSTER_NAME} \
      --user=${KUBE_USER} \
      --kubeconfig=${KUBE_CONFIG}
    
    # 设置当前使用的上下文
    kubectl config use-context ${KUBE_USER}@${CLUSTER_NAME} --kubeconfig=${KUBE_CONFIG}
    
    # 查看生成的配置文件
    kubectl config view --kubeconfig=${KUBE_CONFIG}
    
  rm -rf *.csr
  cp -r /etc/kubernetes/ /etc/kubernetes.bak
  cd /etc/kubernetes/pki
 \cp -rf /root/key/* .
  cd ..
  \cp pki/*.conf .
   rm -rf openssl.conf
  • 应用配置

    • 重启 Docker 和 Kubelet
    • 查看三个kubernetes组件(kubelet,controller-manager,scheduler)的日志,确认是否还有证书过期报错信息。
  • Worker节点证书更新操作

    • 停止docker和kubelet

      systemctl stop docker && systemctl stop kubelet
      
    • 删除kubelet.conf文件,文件一般在/etc/kubernetes目录下。

    • 编辑bootstrap-kubelet.conf文件(文件一般在/etc/kubernetes目录下),修改certificate-authority-data内容,与master节点中的admin.conf文件的该区域内容相同。

    • 备份后删除该目录下的文件rm -rf /var/lib/kubelet/pki

    • 重启所有节点docker和kubelet

      systemctl restart docker && systemctl restart kubelet
      

重启服务

  • 将全部kube-proxy重启
  • 将全部网络插件重启(比如:flannel)

更新权限更新token

  • cp /etc/kubernetes/admin.conf ~/.kube/config
  • kubeadm token list
  • kubeadm token create --ttl=0
  • kubeadm token list
    把获取到的token更新到node节点/etc/kubernetes/bootstrap-kubelet.conf
    重启node节点kubelet
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容