Kubernetes қауіпсіздік ABC: аутентификация, авторизация, аудит

Kubernetes қауіпсіздік ABC: аутентификация, авторизация, аудит

Ерте ме, кеш пе, кез келген жүйенің жұмысында қауіпсіздік мәселесі туындайды: аутентификацияны қамтамасыз ету, құқықтарды бөлу, тексеру және басқа да міндеттер. Kubernetes үшін әлдеқашан жасалған көптеген шешімдер, бұл тіпті өте талап етілетін орталарда да стандарттарға сәйкестікке қол жеткізуге мүмкіндік береді... Дәл сол материал K8s кіріктірілген механизмдерінде жүзеге асырылатын қауіпсіздіктің негізгі аспектілеріне арналған. Ең алдымен, бұл Kubernetes-пен танысуды бастағандар үшін пайдалы болады - қауіпсіздікке қатысты мәселелерді зерттеудің бастапқы нүктесі ретінде.

Түпнұсқалық растама

Kubernetes-те пайдаланушылардың екі түрі бар:

  • Қызметтік тіркелгілер — Kubernetes API басқаратын тіркелгілер;
  • пайдаланушылар — сыртқы тәуелсіз қызметтер басқаратын «қалыпты» пайдаланушылар.

Бұл түрлердің негізгі айырмашылығы мынада: Қызметтік тіркелгілер үшін Kubernetes API-де арнайы нысандар бар (олар былай деп аталады - ServiceAccounts), олар Құпиялар түріндегі нысандарда кластерде сақталған аттар кеңістігіне және авторизация деректерінің жиынына байланыстырылған. Мұндай пайдаланушылар (Қызмет тіркелгілері) негізінен Kubernetes кластерінде іске қосылған процестердің Kubernetes API интерфейсіне кіру құқықтарын басқаруға арналған.

Қарапайым пайдаланушыларда Kubernetes API-де жазбалар жоқ: олар сыртқы механизмдер арқылы басқарылуы керек. Олар кластерден тыс тұратын адамдарға немесе процестерге арналған.

Әрбір API сұрауы қызмет тіркелгісімен, пайдаланушымен байланыстырылады немесе анонимді болып саналады.

Пайдаланушының аутентификация деректері мыналарды қамтиды:

  • Пайдаланушы аты — пайдаланушы аты (әріптерді ескереді!);
  • UID - «пайдаланушы атына қарағанда дәйекті және бірегей» машинада оқылатын пайдаланушы сәйкестендіру жолы;
  • топтар — пайдаланушы жататын топтардың тізімі;
  • қосымша — авторизациялау механизмі пайдаланатын қосымша өрістер.

Kubernetes аутентификация механизмдерінің көп санын пайдалана алады: X509 сертификаттары, Тасымалдаушы таңбалауыштары, аутентификациялау проксиі, HTTP Basic Auth. Осы механизмдерді пайдалана отырып, авторизация схемаларының үлкен санын жүзеге асыруға болады: құпия сөздері бар статикалық файлдан OpenID OAuth2-ге дейін.

Сонымен қатар, бір уақытта бірнеше авторизация схемасын пайдалануға болады. Әдепкі бойынша кластер пайдаланады:

  • қызмет тіркелгісі таңбалауыштары - Қызметтік тіркелгілер үшін;
  • X509 - пайдаланушылар үшін.

ServiceAccounts басқару туралы сұрақ осы мақаланың ауқымынан тыс, бірақ осы мәселемен толығырақ танысқысы келетіндер үшін мынадан бастауды ұсынамын. ресми құжаттама беттері. X509 сертификаттары қалай жұмыс істейтіні туралы мәселені егжей-тегжейлі қарастырамыз.

Пайдаланушыларға арналған сертификаттар (X.509)

Сертификаттармен жұмыс істеудің классикалық әдісі мыналарды қамтиды:

  • негізгі буын:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • сертификат сұрауын жасау:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • Kubernetes кластерінің CA кілттері арқылы сертификат сұрауын өңдеу, пайдаланушы сертификатын алу (сертификат алу үшін әдепкі бойынша мына жерде орналасқан Kubernetes кластерінің CA кілтіне рұқсаты бар тіркелгіні пайдалану керек. /etc/kubernetes/pki/ca.key):
    openssl x509 -req -in ~/.certs/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/.certs/mynewuser.crt -days 500
  • конфигурация файлын құру:
    • кластер сипаттамасы (нақты кластерді орнату үшін CA сертификаты файлының мекенжайы мен орнын көрсетіңіз):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • немесе қалай емесұсынылған опция - түбірлік сертификатты көрсетудің қажеті жоқ (сонда kubectl кластердің api-серверінің дұрыстығын тексермейді):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • пайдаланушыны конфигурация файлына қосу:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • контекст қосу:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • әдепкі контекстік тағайындау:
      kubectl config use-context mynewuser-context

Жоғарыдағы манипуляциялардан кейін файлда .kube/config келесідей конфигурация жасалады:

apiVersion: v1
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/ca.crt
    server: https://192.168.100.200:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: target-namespace
    user: mynewuser
  name: mynewuser-context
current-context: mynewuser-context
kind: Config
preferences: {}
users:
- name: mynewuser
  user:
    client-certificate: /home/mynewuser/.certs/mynewuser.crt
    client-key: /home/mynewuser/.certs/mynewuser.key

Тіркелгілер мен серверлер арасында конфигурацияны тасымалдауды жеңілдету үшін келесі кілттердің мәндерін өңдеу пайдалы:

  • certificate-authority
  • client-certificate
  • client-key

Ол үшін оларда көрсетілген файлдарды base64 көмегімен кодтауға және пернелердің атына жұрнақ қосып, конфигурацияда тіркеуге болады. -data, яғни. алған certificate-authority-data және т.б.

kubeadm бар сертификаттар

Шығарылыммен Кубернеттер 1.15 қолдауының альфа нұсқасының арқасында сертификаттармен жұмыс істеу әлдеқайда жеңіл болды kubeadm утилитасы. Мысалы, пайдаланушы кілттері бар конфигурация файлын жасау келесідей болуы мүмкін:

kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200

NB: Міндетті мекенжайын жарнамалаңыз әдепкі бойынша орналасқан api-сервер конфигурациясынан табуға болады /etc/kubernetes/manifests/kube-apiserver.yaml.

Алынған конфигурация stdout файлына шығарылады. Оны сақтау керек ~/.kube/config пайдаланушы тіркелгісіне немесе орта айнымалысында көрсетілген файлға KUBECONFIG.

Тереңірек қазу

Толығырақ сипатталған мәселелерді түсінгісі келетіндер үшін:

Авторизация

Әдепкі рұқсат етілген тіркелгінің кластерде жұмыс істеу құқығы жоқ. Рұқсаттарды беру үшін Kubernetes авторизациялау механизмін жүзеге асырады.

1.6 нұсқасына дейін Kubernetes деп аталатын авторизация түрін пайдаланды ABAC (Атрибут негізіндегі қол жеткізуді басқару). Ол туралы толық ақпаратты мына жерден табуға болады ресми құжаттама. Бұл тәсіл қазіргі уақытта бұрынғы болып саналады, бірақ оны басқа аутентификация түрлерімен бірге пайдалануға болады.

Кластерге қол жеткізу құқықтарын бөлудің ағымдағы (және неғұрлым икемді) жолы деп аталады RBAC (Рөлге негізделген қол жеткізуді басқару). Нұсқадан бері ол тұрақты деп жарияланды Кубернеттер 1.8. RBAC нақты рұқсат етілмеген барлық нәрсеге тыйым салынған құқықтар үлгісін жүзеге асырады.
RBAC қосу үшін, параметрмен Kubernetes api-серверін бастау керек --authorization-mode=RBAC. Параметрлер манифестте әдепкі бойынша жол бойында орналасқан api-сервер конфигурациясымен орнатылады. /etc/kubernetes/manifests/kube-apiserver.yaml, бөлімінде command. Дегенмен, RBAC әдепкі бойынша әлдеқашан қосылған, сондықтан сіз бұл туралы алаңдамауыңыз керек: оны мән арқылы тексеруге болады. authorization-mode (жоғарыда айтылған kube-apiserver.yaml). Айтпақшы, оның мағыналарының арасында авторизацияның басқа түрлері болуы мүмкін (node, webhook, always allow), бірақ біз олардың қарастырылуын материал шеңберінен тыс қалдырамыз.

Айтпақшы, біз жариялап қойғанбыз мақала RBAC-пен жұмыс істеу принциптері мен ерекшеліктерінің жеткілікті егжей-тегжейлі сипаттамасымен, сондықтан әрі қарай мен негіздердің және мысалдардың қысқаша тізімімен шектелемін.

Келесі API нысандары RBAC арқылы Kubernetes жүйесінде кіруді басқару үшін пайдаланылады:

  • Role и ClusterRole — қол жеткізу құқықтарын сипаттауға қызмет ететін рөлдер:
  • Role аттар кеңістігіндегі құқықтарды сипаттауға мүмкіндік береді;
  • ClusterRole - кластер ішінде, соның ішінде түйіндер, ресурстарға жатпайтын URL мекенжайлары (яғни, Kubernetes ресурстарына қатысы жоқ - мысалы, кластерге тән нысандар) /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - байлау үшін қолданылады Role и ClusterRole пайдаланушыға, пайдаланушы тобына немесе ServiceAccount.

Role және RoleBinding нысандары аттар кеңістігімен шектелген, яғни. бірдей аттар кеңістігінде болуы керек. Дегенмен, RoleBinding жалпы рұқсаттар жинағын жасауға және олардың көмегімен қол жеткізуді басқаруға мүмкіндік беретін ClusterRole сілтемесіне сілтеме жасай алады.

Рөлдер мыналарды қамтитын ережелер жиынын пайдаланып құқықтарды сипаттайды:

  • API топтары - қараңыз ресми құжаттама apiGroups және шығыс арқылы kubectl api-resources;
  • ресурстар (ресурстар: pod, namespace, deployment және т.б.);
  • Етістік (етістіктер: set, update және т.б.).
  • ресурс атаулары (resourceNames) - осы түрдегі барлық ресурстарға емес, белгілі бір ресурсқа кіруді қамтамасыз ету қажет болған жағдайда.

Kubernetes авторизациясының егжей-тегжейлі талдауын бетте табуға болады ресми құжаттама. Оның орнына (дәлірек айтсақ, бұған қосымша) мен оның жұмысын суреттейтін мысалдар келтіремін.

RBAC нысандарының мысалдары

Қарапайым Role, бұл подкасттардың тізімі мен күйін алуға және оларды аттар кеңістігінде бақылауға мүмкіндік береді target-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: target-namespace
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Мысал: ClusterRole, бұл сізге блоктардың тізімі мен күйін алуға және оларды кластер бойынша бақылауға мүмкіндік береді:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # секции "namespace" нет, так как ClusterRole задействует весь кластер
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Мысал: RoleBinding, бұл пайдаланушыға мүмкіндік береді mynewuser аттар кеңістігіндегі «оқу» бөлімдері my-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: target-namespace
subjects:
- kind: User
  name: mynewuser # имя пользователя зависимо от регистра!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # здесь должно быть “Role” или “ClusterRole”
  name: pod-reader # имя Role, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

Оқиға аудиті

Схемалық түрде Кубернетес архитектурасын келесідей көрсетуге болады:

Kubernetes қауіпсіздік ABC: аутентификация, авторизация, аудит

Сұраныстарды өңдеуге жауапты негізгі Kubernetes құрамдас бөлігі болып табылады api-сервер. Кластердегі барлық операциялар ол арқылы өтеді. Осы ішкі механизмдер туралы толығырақ мақаладан оқи аласыз «kubectl іске қосылған кезде Kubernetes ішінде не болады?«.

Жүйені тексеру - әдепкі бойынша өшірілген Kubernetes-тегі қызықты мүмкіндік. Ол барлық қоңырауларды Kubernetes API жүйесіне тіркеуге мүмкіндік береді. Сіз болжағандай, бақылауға және кластердің күйін өзгертуге қатысты барлық әрекеттер осы API арқылы орындалады. Оның мүмкіндіктерінің жақсы сипаттамасын (әдеттегідей) табуға болады ресми құжаттама K8s. Әрі қарай тақырыпты қарапайым тілде беруге тырысамын.

Осылайша, аудитті жүргізуге мүмкіндік береді, біз api-сервердегі контейнерге үш қажетті параметрді беруіміз керек, олар төменде толығырақ сипатталған:

  • --audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
  • --audit-log-path=/var/log/kube-audit/audit.log
  • --audit-log-format=json

Осы үш қажетті параметрге қоса, аудитке қатысты көптеген қосымша параметрлер бар: журналды айналдырудан веб-хук сипаттамаларына дейін. Журналды айналдыру параметрлерінің мысалы:

  • --audit-log-maxbackup=10
  • --audit-log-maxsize=100
  • --audit-log-maxage=7

Бірақ біз оларға толығырақ тоқталмаймыз - барлық мәліметтерді мына жерден таба аласыз kube-аписервер құжаттамасы.

Жоғарыда айтылғандай, барлық параметрлер манифестте api-сервер конфигурациясымен орнатылған (әдепкі бойынша /etc/kubernetes/manifests/kube-apiserver.yaml), бөлімінде command. Қажетті 3 параметрге оралайық және оларды талдаймыз:

  1. audit-policy-file — аудит саясатын сипаттайтын YAML файлына жол. Біз оның мазмұнына кейінірек ораламыз, бірақ қазір файлды api-сервер процесі оқуға болатынын ескертемін. Сондықтан оны контейнердің ішіне орнату қажет, ол үшін конфигурацияның сәйкес бөлімдеріне келесі кодты қосуға болады:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — журнал файлына жол. Жол сондай-ақ api-сервер процесіне қол жетімді болуы керек, сондықтан оны орнатуды дәл осылай сипаттаймыз:
      volumeMounts:
        - mountPath: /var/log/kube-audit
          name: logs
          readOnly: false
      volumes:
      - hostPath:
          path: /var/log/kube-audit
          type: DirectoryOrCreate
        name: logs
  3. audit-log-format — аудит журналының пішімі. Әдепкі болып табылады json, бірақ бұрынғы мәтін пішімі де қол жетімді (legacy).

Аудит саясаты

Енді тіркеу саясатын сипаттайтын аталған файл туралы. Аудит саясатының бірінші тұжырымдамасы болып табылады level, тіркеу деңгейі. Олар келесідей:

  • None - журналға жазбау;
  • Metadata — журнал сұрауының метадеректері: пайдаланушы, сұрау уақыты, мақсатты ресурс (под, аттар кеңістігі және т.б.), әрекет түрі (етістік) және т.б.;
  • Request — журналдың метадеректері және сұраныстың негізгі бөлігі;
  • RequestResponse — журналдың метадеректері, сұраныстың негізгі бөлігі және жауап мәтіні.

Соңғы екі деңгей (Request и RequestResponse) ресурстарға қол жеткізе алмаған сұрауларды (ресурстар емес url деп аталатын кірулер) журналға қоймаңыз.

Сондай-ақ барлық өтініштер орындалады бірнеше кезең:

  • RequestReceived — сұранысты процессор алатын және процессорлар тізбегі бойынша әрі қарай әлі берілмеген кезең;
  • ResponseStarted — жауап тақырыптары жіберіледі, бірақ жауап органы жіберілгенге дейін. Ұзақ орындалатын сұраулар үшін жасалған (мысалы, watch);
  • ResponseComplete — жауап органы жіберілді, басқа ақпарат жіберілмейді;
  • Panic — оқиғалар әдеттен тыс жағдай анықталған кезде жасалады.

Қолдануға болатын кез келген қадамдарды өткізіп жіберу үшін omitStages.

Саясат файлында әртүрлі тіркеу деңгейлері бар бірнеше бөлімдерді сипаттай аламыз. Саясат сипаттамасында табылған бірінші сәйкестік ережесі қолданылады.

Kubelet демоны манифесттегі өзгерістерді api-сервер конфигурациясымен бақылайды және егер анықталған болса, api-серверімен контейнерді қайта іске қосады. Бірақ маңызды деталь бар: саясат файлындағы өзгерістер ол еленбейді. Саясат файлына өзгертулер енгізгеннен кейін api-серверді қолмен қайта іске қосу қажет болады. Api-сервер ретінде іске қосылғандықтан статикалық блок, командасы kubectl delete қайта іске қосылуына себеп болмайды. Мұны қолмен орындауға тура келеді docker stop аудит саясаты өзгертілген kube-мастерлерде:

docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')

Аудитті іске қосқан кезде мұны есте сақтау маңызды kube-аписерверге жүктеме артады. Атап айтқанда, сұрау контекстін сақтауға арналған жадты тұтыну артады. Журналға жазу жауап тақырыбы жіберілгеннен кейін ғана басталады. Жүктеме аудит саясатының конфигурациясына да байланысты.

Саясаттың мысалдары

Мысалдар арқылы саясат файлдарының құрылымын қарастырайық.

Мұнда қарапайым файл policyдеңгейінде барлығын тіркеу Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

Саясатта пайдаланушылар тізімін көрсетуге болады (Users и ServiceAccounts) және пайдаланушы топтары. Мысалы, осылайша біз жүйе пайдаланушыларын елемейміз, бірақ қалғандарының барлығын деңгейде журналға енгіземіз Request:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: None
    userGroups:
      - "system:serviceaccounts"
      - "system:nodes"
    users:
      - "system:anonymous"
      - "system:apiserver"
      - "system:kube-controller-manager"
      - "system:kube-scheduler"
  - level: Request

Сондай-ақ мақсаттарды сипаттауға болады:

  • аттар кеңістігі (namespaces);
  • Етістік (етістіктер: get, update, delete және басқалар);
  • ресурстар (ресурстар, атап айтқанда: pod, configmaps т.б.) және ресурстар топтары (apiGroups).

Назар аударыңыз! Ресурстар мен ресурстар топтарын (API топтары, яғни apiGroups), сондай-ақ олардың кластерде орнатылған нұсқаларын пәрмендер арқылы алуға болады:

kubectl api-resources
kubectl api-versions

Келесі аудит саясаты үздік тәжірибелерді көрсету ретінде берілген Alibaba Cloud құжаттамасы:

apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Не логировать стадию RequestReceived
omitStages:
  - "RequestReceived"
rules:
  # Не логировать события, считающиеся малозначительными и не опасными:
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: "" # это api group с пустым именем, к которому относятся
                  # базовые ресурсы Kubernetes, называемые “core”
        resources: ["endpoints", "services"]
  - level: None
    users: ["system:unsecured"]
    namespaces: ["kube-system"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["configmaps"]
  - level: None
    users: ["kubelet"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    userGroups: ["system:nodes"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    users:
      - system:kube-controller-manager
      - system:kube-scheduler
      - system:serviceaccount:kube-system:endpoint-controller
    verbs: ["get", "update"]
    namespaces: ["kube-system"]
    resources:
      - group: "" # core
        resources: ["endpoints"]
  - level: None
    users: ["system:apiserver"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["namespaces"]
  # Не логировать обращения к read-only URLs:
  - level: None
    nonResourceURLs:
      - /healthz*
      - /version
      - /swagger*
  # Не логировать сообщения, относящиеся к типу ресурсов “события”:
  - level: None
    resources:
      - group: "" # core
        resources: ["events"]
  # Ресурсы типа Secret, ConfigMap и TokenReview могут содержать  секретные данные,
  # поэтому логируем только метаданные связанных с ними запросов
  - level: Metadata
    resources:
      - group: "" # core
        resources: ["secrets", "configmaps"]
      - group: authentication.k8s.io
        resources: ["tokenreviews"]
  # Действия типа get, list и watch могут быть ресурсоёмкими; не логируем их
  - level: Request
    verbs: ["get", "list", "watch"]
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для стандартных ресурсов API
  - level: RequestResponse
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для всех остальных запросов
  - level: Metadata

Аудит саясатының тағы бір жақсы мысалы болып табылады GCE-де қолданылатын профиль.

Аудиторлық оқиғаларға жылдам әрекет ету мүмкін вебхукты сипаттаңыз. Бұл мәселе қамтылған ресми құжаттама, Мен оны осы мақаланың шеңберінен тыс қалдырамын.

Нәтижелері

Мақалада жекелендірілген пайдаланушы тіркелгілерін жасауға, олардың құқықтарын бөлуге және әрекеттерін жазуға мүмкіндік беретін Kubernetes кластерлеріндегі негізгі қауіпсіздік тетіктеріне шолу берілген. Теориялық немесе тәжірибе жүзінде осындай мәселелермен бетпе-бет келгендерге пайдалы болады деп сенемін. Сондай-ақ, мен сізге «PS» бөлімінде берілген Kubernetes-тегі қауіпсіздік тақырыбына арналған басқа материалдардың тізімін оқуды ұсынамын - мүмкін олардың арасында сіз өзіңізге қатысты мәселелер бойынша қажетті мәліметтерді таба аласыз.

PS

Біздің блогта да оқыңыз:

Ақпарат көзі: www.habr.com

пікір қалдыру