Service Mesh (ASM) terintegrasi dengan plugin Open Policy Agent (OPA), memungkinkan kontrol akses detail halus untuk aplikasi Anda melalui kebijakan OPA. ASM memungkinkan Anda menentukan kebijakan ini pada control plane dan mendorongnya ke kluster data plane. Topik ini menjelaskan cara menggunakan fitur ini untuk mengontrol akses berdasarkan kriteria seperti URL permintaan dan token dalam header permintaan.
Prasyarat
Instans ASM versi 1.9.7 atau yang lebih baru. Untuk informasi selengkapnya, lihat Buat instans ASM.
Injeksi sidecar otomatis diaktifkan untuk namespace default. Untuk informasi selengkapnya, lihat Aktifkan injeksi otomatis.
Latar Belakang
Sebagai proyek inkubasi yang dihosting oleh CNCF, Open Policy Agent (OPA) adalah mesin kebijakan yang dapat digunakan untuk menerapkan kontrol akses detail halus pada aplikasi Anda. Sebagai mesin kebijakan tujuan umum, OPA dapat dideploy sebagai layanan mandiri bersama layanan mikro. Untuk melindungi aplikasi, setiap permintaan ke layanan mikro harus melalui otorisasi sebelum diproses. Untuk memeriksa otorisasi tersebut, layanan mikro melakukan panggilan API ke OPA guna menentukan apakah permintaan tersebut diizinkan.
Langkah 1: Aktifkan plugin OPA dan kontrol cakupan
-
Login ke Konsol ASM. Di panel navigasi kiri, pilih .
-
Pada halaman Mesh Management, klik nama instans ASM. Di panel navigasi kiri, pilih .
Pada halaman OPA Policy, pilih Enable Open Policy Agent (OPA) Plugin dan Enable OPA Injection Scope Control, klik Enable OPA, lalu klik OK pada kotak dialog Note.
Langkah 2: Buat kebijakan OPA
Anda membuat resource ASMOPAPolicy pada control plane ASM. ASM kemudian mendorong resource ini ke kluster data plane, tempat mesin OPA di setiap Pod terkait menggunakannya untuk menerapkan kontrol akses detail halus.
Opsi 1: Gunakan Konsol ASM
-
Login ke Konsol ASM. Di panel navigasi kiri, pilih .
-
Pada halaman Mesh Management, klik nama instans ASM. Di panel navigasi kiri, pilih .
Pada halaman OPA Policy, klik Create. Pilih namespace default, atur Name kebijakan OPA menjadi bookinfo-opa, lalu klik Add Matching Label. Atur Name menjadi version dan Value menjadi v1. Salin aturan Rego berikut ke dalam kotak teks, lalu klik Create.
Opsi 2: Gunakan kubectl
Buat file bernama opa.yaml dengan konten berikut.
CatatanSaat menentukan kebijakan OPA untuk sebuah Pod, Anda hanya boleh menyertakan satu field
default allow. Jika beberapa kebijakan OPA berlaku untuk satu Pod dan masing-masing mendefinisikan fielddefault allow, maka fielddefault allowganda tersebut akan menyebabkan pembaruan dinamis gagal.Cakup kebijakan menggunakan label. Aturan Rego yang tidak valid dapat membuat layanan tidak dapat diakses.
Mesin eksekusi OPA dan kontainer aplikasi berjalan dalam Pod yang sama serta menggunakan Port 15081 dan 9191.
Kebijakan OPA secara default bernilai
allow = false. Jangan mendefinisikan ulangdefault allowuntuk menghindari konflik.
Parameter
Deskripsi
specAturan kebijakan, ditulis dalam bahasa Rego. Untuk informasi selengkapnya tentang sintaksis Rego, lihat Rego.
workloadSelectorMenentukan cakupan kebijakan dalam namespace. Jika dihilangkan, kebijakan berlaku untuk semua Pod dalam namespace tersebut. Jika ditentukan, kebijakan hanya berlaku untuk Pod dengan label yang sesuai.
user_rolesMemberikan izin peran kepada pengguna. Dalam contoh ini, pengguna
guest1diberikan peranguest, dan penggunaadmin1diberikan peranadmin.role_permsMenentukan izin setiap peran. Dalam contoh ini, peran
guestdapat mengakses /productpage, sedangkan peranadmindapat mengakses /productpage dan /api/v1/products.Jalankan perintah berikut untuk membuat kebijakan OPA.
Untuk informasi selengkapnya tentang cara menghubungkan ke instans ASM menggunakan kubectl, lihat Gunakan kubectl pada control plane untuk mengakses resource Istio.
kubectl apply -f opa.yaml
Langkah 3: Injeksikan proxy OPA
Deploy aplikasi sampel Bookinfo ke instans ASM dan pastikan bahwa ASM telah menginjeksikan proxy OPA ke setiap Pod.
Deploy aplikasi sampel Bookinfo ke instans ASM. Untuk informasi selengkapnya, lihat Deploy aplikasi di kluster yang terkait dengan instans ASM.
Buat ingress gateway, gateway Istio, dan virtual service. Untuk informasi selengkapnya, lihat Gunakan resource Istio untuk merutekan traffic berdasarkan versi.
Periksa apakah proxy OPA telah diinjeksikan ke setiap Pod aplikasi.
-
Masuk ke Konsol ACK. Di panel navigasi kiri, klik Clusters.
-
Pada halaman Clusters, klik nama kluster Anda. Di panel navigasi kiri, klik .
Pada halaman Pods, pilih default dari daftar drop-down Namespace lalu klik nama Pod aplikasi target.
Pada tab Containers, verifikasi bahwa Pod berisi kontainer istio-proxy (sidecar proxy) dan opa-istio (proxy OPA).
-
Langkah 4: Verifikasi kebijakan kontrol akses OPA
Jalankan perintah berikut untuk mengakses /productpage.
curl -X GET http://<INGRESS_GATEWAY_IP>/productpage --user guest1:password -IOutput yang diharapkan:
HTTP/1.1 200 OKJalankan perintah berikut untuk mengakses
/api/v1/products.curl -X GET http://<INGRESS_GATEWAY_IP>/api/v1/products --user guest1:password -IOutput yang diharapkan:
HTTP/1.1 403 ForbiddenHasil ini mengonfirmasi bahwa pengguna guest1, dengan peran guest, dapat mengakses
/productpagetetapi ditolak saat mengakses/api/v1/products.Jalankan perintah berikut untuk mengakses
/productpage.curl -X GET http://<INGRESS_GATEWAY_IP>/productpage --user admin1:password -IOutput yang diharapkan:
HTTP/1.1 200 OKJalankan perintah berikut untuk mengakses
/api/v1/products.curl -X GET http://<INGRESS_GATEWAY_IP>/api/v1/products --user admin1:password -IOutput yang diharapkan:
HTTP/1.1 200 OKHasil ini menunjukkan bahwa
admin1diberikan peranadmin.admin1dapat mengakses baik/productpagemaupun/api/v1/products. Hal ini menunjukkan bahwa kebijakan kontrol akses OPA berfungsi sebagaimana mestinya.
Langkah 5: Perbarui kebijakan OPA secara dinamis
Jalankan perintah berikut untuk mengubah kebijakan OPA.
kubectl edit asmopapolicy bookinfo-opa -n default Pada output, edit kebijakan OPA untuk memberikan guest1 kedua peran guest dan admin.
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: bookinfo-opa
namespace: default
spec:
policy: |
package istio.authz
import input.attributes.request.http as http_request
allow {
roles_for_user[r]
required_roles[r]
}
roles_for_user[r] {
r := user_roles[user_name][_]
}
required_roles[r] {
perm := role_perms[r][_]
perm.method = http_request.method
perm.path = http_request.path
}
user_name = parsed {
[_, encoded] := split(http_request.headers.authorization, " ")
[parsed, _] := split(base64url.decode(encoded), ":")
}
user_roles = {
"guest1": ["guest", "admin"],
"admin1": ["admin"]
}
role_perms = {
"guest": [
{"method": "GET", "path": "/productpage"},
],
"admin": [
{"method": "GET", "path": "/productpage"},
{"method": "GET", "path": "/api/v1/products"},
],
}user_roles: Memberikan izin peran kepada pengguna. Dalam contoh ini, pengguna
guest1diberikan peranguestdanadmin, sedangkan penggunaadmin1diberikan peranadmin.role_perms: Menentukan izin setiap peran. Dalam contoh ini, peran
guestdapat mengakses /productpage, sedangkan peranadmindapat mengakses /productpage dan /api/v1/products.
Langkah 6: Verifikasi pembaruan dinamis
Jalankan perintah berikut untuk mengakses /productpage.
curl -X GET http://<INGRESS_GATEWAY_IP>/productpage --user guest1:password -IOutput yang diharapkan:
HTTP/1.1 200 OKJalankan perintah berikut untuk mengakses /api/v1/products.
curl -X GET http://<INGRESS_GATEWAY_IP>/api/v1/products --user guest1:password -IOutput yang diharapkan:
HTTP/1.1 200 OKSebelumnya,
guest1hanya dapat mengakses/productpage. Setelah pembaruan,guest1juga dapat mengakses/api/v1/products, yang mengonfirmasi bahwa pembaruan kebijakan dinamis berhasil.
Skenario
Skenario 1: Otorisasi permintaan berdasarkan klaim JWT
Skenario ini menunjukkan cara mengotorisasi permintaan berdasarkan klaim dalam JSON Web Token (JWT). Kebijakan ini memverifikasi JWT dalam header permintaan, sehingga hanya permintaan tepercaya yang dapat mengakses aplikasi.
ASMOPAPolicy berikut hanya mengizinkan akses ke aplikasi Productpage ketika permintaan menggunakan metode GET, klaim Role dalam JWT bernilai guest, dan klaim userGroup bernilai visitor.
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: policy-jwt
namespace: default
spec:
policy: |
package istio.authz
allow {
input.attributes.request.http.method == "GET"
input.parsed_path[0] == "productpage"
# set certificate 'B41BD5F462719C6D6118E673A2389'
io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
claims.Role == "guest"
claims.userGroup == "visitor"
}
claims := payload {
[_, payload, _] := io.jwt.decode(bearer_token)
}
bearer_token := t {
v := input.attributes.request.http.headers.authorization
startswith(v, "Bearer ")
t := substring(v, count("Bearer "), -1)
}input.attributes.request.http.method: Metode permintaan. Dalam contoh ini, nilainya adalah
GET.input.parsed_path[0]: Aplikasi yang diakses.
claims.Role: Membatasi JWT. Dalam contoh ini,
Roleharus bernilaiguest.claims.userGroup: Membatasi JWT. Dalam contoh ini,
userGroupharus bernilaivisitor.
Gunakan tool JWT untuk mengencode informasi permintaan seperti Role dan userGroup ke dalam string JWT. Di bagian Payload tool encoding JWT, selain Role dan userGroup, Anda juga perlu mengatur name menjadi guest1, kunci penandatanganan menjadi B41BD5F462719C6D6118, dan memilih algoritma HS256. Setelah diencode, Anda dapat memperoleh string JWT untuk otorisasi permintaan.
Jalankan perintah berikut untuk mengakses aplikasi Productpage.
curl --location --request GET 'http://<INGRESS_GATEWAY_IP>/productpage' \
--header 'Authorization: Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3Vlc3QxIiwiUm9sZSI6Imd1ZXN0IiwidXNlckdyb3VwIjoidmlzaXRvciJ9.44OnUFZwOzSWzC7hyVfcle-uYk8byv7q_BBxS10AEWc'Output yang diharapkan:
HTTP/1.1 200 OKRespons 200 menunjukkan bahwa permintaan GET ke aplikasi Productpage berhasil. Hal ini terjadi ketika permintaan mencakup Token JWT dengan klaim Role bernilai guest dan klaim userGroup bernilai visitor. Jika Token JWT yang salah digunakan atau permintaan tidak berisi Token JWT, respons 403 akan dikembalikan, yang menunjukkan bahwa akses ke aplikasi Productpage gagal.
Skenario 2: Batasi badan permintaan HTTP
Skenario ini menunjukkan cara mengotorisasi permintaan dengan memvalidasi bidang dalam badan permintaan HTTP terhadap klaim dalam JWT.
ASMOPAPolicy berikut hanya mengizinkan akses ke aplikasi Productpage ketika permintaan menggunakan metode GET, username dalam badan permintaan cocok dengan klaim Role dalam JWT, dan klaim userGroup bernilai manager.
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: policy-body
namespace: default
spec:
policy: |
package istio.authz
allow {
input.attributes.request.http.method == "GET"
input.parsed_path[0] == "productpage"
io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
claims.Role == input.parsed_body.username
claims.userGroup == "manager"
}
claims := payload {
[_, payload, _] := io.jwt.decode(bearer_token)
}
bearer_token := t {
v := input.attributes.request.http.headers.authorization
startswith(v, "Bearer ")
t := substring(v, count("Bearer "), -1)
}input.attributes.request.http.method: Metode permintaan. Dalam contoh ini, nilainya adalah
GET.input.parsed_path[0]: Aplikasi yang diakses.
claims.Role: Membatasi JWT. Dalam contoh ini, nilainya diatur ke
input.parsed_body.username, yang mensyaratkan bahwausernamedalam badan permintaan harus cocok dengan klaimRoledalam JWT.claims.userGroup: Membatasi JWT. Dalam contoh ini,
userGroupharus bernilaimanager.
Gunakan tool JWT untuk mengencode informasi permintaan seperti Role dan userGroup ke dalam string JWT.
Jalankan perintah berikut untuk mengakses aplikasi Productpage.
curl --location --request GET 'http://<INGRESS_GATEWAY_IP>/productpage' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3Vlc3QxIiwiUm9sZSI6ImFkbWluIiwidXNlckdyb3VwIjoibWFuYWdlciJ9.pAUvTeONHF-i5Ps-EUYYXk-hnaz-j-ZgP_wXJZMBiR0' \
--header 'Content-Type: application/json' \
--header 'Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.YRz90g.GT34_5BqlFTwGqabZk_qGZzxYQ0' \
--data-raw '{
"username":"admin",
"password":"12****"
}'Output yang diharapkan:
HTTP/1.1 200 OKRespons 200 OK menunjukkan bahwa permintaan GET dapat mengakses aplikasi Productpage jika username dalam badan permintaan cocok dengan klaim Role dalam JWT dan klaim userGroup dalam JWT bernilai manager. JWT yang tidak valid atau tidak ada akan menghasilkan respons 403 Forbidden.
Skenario 3: Batasi informasi kontekstual lebih lanjut
Berdasarkan Skenario 2, Anda dapat membatasi informasi kontekstual lebih lanjut. Misalnya, Anda dapat mensyaratkan bahwa klaim username dalam JWT harus berada dalam daftar bookinfo_managers.
ASMOPAPolicy berikut hanya mengizinkan akses ke aplikasi Productpage ketika permintaan menggunakan metode GET, username dalam badan permintaan cocok dengan klaim Role dalam JWT, klaim username dalam JWT berada dalam daftar bookinfo_managers, dan klaim userGroup bernilai manager.
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: policy-range
namespace: default
spec:
policy: |
package istio.authz
bookinfo_managers = [{"name": "user1"}, {"name": "user2"}, {"name": "user3"}]
allow {
input.attributes.request.http.method == "GET"
input.parsed_path[0] == "productpage"
io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
claims.Role == input.parsed_body.username
claims.userGroup == "manager"
claims.username == bookinfo_managers[_].name
}
claims := payload {
[_, payload, _] := io.jwt.decode(bearer_token)
}
bearer_token := t {
v := input.attributes.request.http.headers.authorization
startswith(v, "Bearer ")
t := substring(v, count("Bearer "), -1)
}input.attributes.request.http.method: Metode permintaan. Dalam contoh ini, nilainya adalah
GET.input.parsed_path[0]: Aplikasi yang diakses.
claims.Role: Membatasi JWT. Dalam contoh ini, nilainya diatur ke
input.parsed_body.username, yang mensyaratkan bahwa username dalam badan permintaan harus cocok dengan klaim Role dalam JWT.claims.userGroup: Membatasi JWT. Dalam contoh ini,
userGroupharus bernilaimanager.claims.username: Membatasi JWT. Dalam contoh ini, nilainya diatur ke
bookinfo_managers[_].name, yang mensyaratkan bahwa klaimusernamedalam JWT harus ada dalam daftarbookinfo_managers.
Gunakan tool JWT untuk mengencode informasi permintaan ke dalam string JWT.
Jalankan perintah berikut untuk mengakses aplikasi Productpage.
curl --location --request GET 'http://<INGRESS_GATEWAY_IP>/productpage' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiUm9sZSI6ImFkbWluIiwidXNlckdyb3VwIjoibWFuYWdlciJ9.2X0Fmb96jBexLcVm_55t8ZY6XveSxUAsQ1j3ar5dI_g' \
--header 'Content-Type: application/json' \
--header 'Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.YRz90g.GT34_5BqlFTwGqabZk_qGZzxYQ0' \
--data-raw '{
"username":"admin",
"password":"12****"
}'Output yang diharapkan:
HTTP/1.1 200 OKRespons 200 OK menunjukkan bahwa permintaan GET dapat mengakses aplikasi Productpage jika username dalam badan permintaan cocok dengan klaim Role dalam JWT, klaim username dalam JWT ada dalam daftar bookinfo_managers, dan klaim userGroup dalam JWT bernilai manager. JWT yang tidak valid atau tidak ada akan menghasilkan respons 403 Forbidden.
FAQ
Bagaimana cara memeriksa kebijakan OPA pada sebuah Pod?
Mesin OPA berjalan sebagai sidecar dalam Pod aplikasi. Untuk melihat semua kebijakan OPA yang berlaku pada sebuah Pod, login ke Pod tersebut dan jalankan perintah berikut:
curl 127.0.0.1:15081/v1/policiesBagaimana cara menguji sintaksis Rego?
OPA menyediakan tool pengujian online untuk memvalidasi kebijakan Rego.
Referensi
Jika sebelumnya Anda menggunakan ConfigMap untuk mengonfigurasi kebijakan OPA, lihat topik berikut: