天天看點

ZooKeeper系統模型之ACL。權限模式:Scheme授權對象:ID權限:PermissionACL管理

         ZooKeeper的ACL權限控制和Unix/Linux作業系統的ACL有一些差別,讀者可以從三個方面來了解ACL機制,分别是:權限控制(Scheme)、授權對象(ID)和權限(Permission),通常使用“scheme:id:permission”來辨別一個有效的ACL資訊。

權限模式:Scheme

        權限模式用來确定權限驗證中使用校驗政策。在ZooKeeper中,開發人員使用最多的就是以下四種權限模式。

IP

IP模式通過IP位址粒度來進行權限控制,例如配置了“ip:192.168.0.110”,即表示權限控制都是針對這個IP位址的。同時,IP模式也支援按照網段的方式進行配置,例如“ip:192.168.0.1/24”表示針對192.168.0.*這個IP段進行權限控制。

Digest

Digest是最常用的權限控制模式,也更符合我們對于權限控制的認識,其以類似于“username:password”形式的權限辨別來進行權限配置,便于區分不同應用來進行權限控制。

當我們通過“username:password”形式配置了權限辨別後,ZooKeeper會對其先後進行兩次編碼處理,分别是SHA-1算法加密和BASE64編碼,其具體實作由DigestAuthenticationProvider.generateDigest(String idPassword)函數進行封裝,下面代碼所示為使用該函數進行“username:password”編碼的一個執行個體。

public class DigestAuthenticationProviderUsage {

    public static void main(String[] args) {

        try {

            System.out.println(DigestAuthenticationProvider.generateDigest("foo:zk-book"));

        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();

        }

    }

}

運作程式,輸出結果如下:

ZooKeeper系統模型之ACL。權限模式:Scheme授權對象:ID權限:PermissionACL管理
從上面的運作結果中可以看出,“username:password”最終會被混淆為一個無法辨識的字元串。

World

World是一種最開放的權限控制模式,從其名字中也可以看出,事實上這種權限控制方式幾乎沒有任何作用,資料節點的通路權限對所有使用者開放,即所有使用者都可以在不進行任何權限校驗的情況下操作ZooKeeper上的資料。另外,World模式也可以看作是一種特殊的Digest模式,他隻有一個權限辨別,即“world:anyone”。

Super

        Super模式,顧名思義就是超級使用者的意思,也是一種特殊的Digest模式。在Super模式下,超級使用者可以對任意ZooKeeper上的資料節點進行任何操作。

授權對象:ID

        授權對象指的是權限賦予的使用者或一個指定實體,例如IP位址或是機器等。在不同的權限模式下,授權對象是不同的,下表中列出了各個權限模式和授權對象之間的對應關系。

權限模式 授權對象
IP 通常是一個IP位址或是IP段,例如“192.168.0.110”或“192.168.0.1/24”
Digest 自定義,通常是“username:BASE64(SHA-1(username:password))”,例如“foo:kWN6aNSbjcKWPqjiV7cg0N24raU=”
World 隻有一個ID:"anyone"
Super 與Digest模式一緻

權限:Permission

        權限就是指那些通過權限檢查後可以被允許執行的操作。在ZooKeeper中,所有對資料的操作權限分為以下五大類:

  • CREATE(C):資料節點的建立權限,允許授權對象在該資料節點下建立子節點。
  • DELETE(D):子節點的删除權限,允許授權對象删除該資料節點的子節點。
  • READ(R):資料節點的讀取權限,允許授權對象通路該資料節點并讀取其資料内容或子節點清單等。
  • WRITE(W):資料節點的更新權限,允許授權對象對該資料節點進行更新操作。
  • ADMIN(A):資料節點的管理權限,允許授權對象對該資料節點進行ACL相關的設定操作。

權限擴充體系

        在上文中,我們已經講解了ZooKeeper預設提供的IP、Digest、World和Super這四種權限模式,在絕大部分的場景下,這四種權限模式已經能夠很好的實作權限控制的目的。同時ZooKeeper提供了特殊的權限控制插件體系,允許開發人員通過指定方式對ZooKeeper的權限進行擴充。這些擴充的權限控制方式就像插件一樣插入到ZooKeeper的權限體系中去,是以在ZooKeeper的官方文檔中,也稱該機制為“Pluggable ZooKeeper Authentication”。

實作自定義權限控制器

        要實作自定義權限控制器非常簡單,ZooKeeper定義了一個标準權限控制器需要實作的接口:org.apache.zookeeper.server.auth.AuthenticationProvider,其接口定義如下圖所示。

ZooKeeper系統模型之ACL。權限模式:Scheme授權對象:ID權限:PermissionACL管理
ZooKeeper系統模型之ACL。權限模式:Scheme授權對象:ID權限:PermissionACL管理

        使用者可以基于該接口來進行自定義權限控制器的實作。事實上,在前面内容中提到的幾個權限模式,對應的就是ZooKeeper自帶的DigestAuthenticationProvider和IPAuthenticationProvider兩個權限控制器。

注冊自定義權限控制器

        完成自定義權限控制器的開發後,接下來就需要将該權限控制器注冊到ZooKeeper伺服器中去了。ZooKeeper支援通過系統屬性和配置檔案兩種方式來注冊自定義的權限控制器。

  • 系統屬性 -Dzookeeper.authProvider.X

在ZooKeeper啟動參數中配置類似于如下的系統屬性:

-Dzookeeper.authProvider.1=com.zkbook.CustomAuthenticationProvider

  • 配置檔案方式

在zoo.cfg配置檔案中配置類似于如下的配置項:

authProvider.1=com.zkbook.CustomAuthenticationProvider

        對于權限控制器的注冊,ZooKeeper采用了延遲加載的政策,即隻有在第一次處理包含權限控制的用戶端請求時,才會進行權限控制器的初始化。同時,ZooKeeper還會将所有的權限控制器都注冊到ProviderRegistry中去。在具體的實作中,ZooKeeper首先會将DigestAuthenticationProvider和IPAuthenticationProvider這兩個預設的控制器初始化,然後通過掃描zookeeper.authProvider.這一系統屬性,擷取到所有使用者配置的自定義權限控制器,并完成其初始化。

ACL管理

        講解完ZooKeeper的ACL及其擴充機制後,我們來看看如何進行ACL管理。

設定ACL

        通過zkCli腳本登入ZooKeeper伺服器後,可以通過兩種方式進行ACL的設定。一種是在資料節點建立的同時進行ACL權限的設定,命名格式如下:

  • create [-s] [-e] path data acl

        具體使用如下所示。

ZooKeeper系統模型之ACL。權限模式:Scheme授權對象:ID權限:PermissionACL管理

        另一種方式則是使用setAcl命名單獨對已經存在的資料節點進行ACL設定:

  • setAcl path acl

         具體使用如下所示。

ZooKeeper系統模型之ACL。權限模式:Scheme授權對象:ID權限:PermissionACL管理

Super模式的用法

        根據ACL權限控制的原理,一旦對一個資料節點設定了ACL權限控制,那麼其他沒有被授權的ZooKeeper用戶端将無法通路該資料節點,這的确很好的保證了ZooKeeper的資料安全。但同時,ACL權限控制也給ZooKeeper的運維人員帶來了一個困擾:如果一個持久資料節點包含了ACL權限控制,而其建立者用戶端已經退出或已不再使用,那麼這些資料節點該如何清理呢?這個時候,就需要在ACL的Super模式下,使用超級管理者權限來進行處理了。要使用超級管理者權限,首先需要在ZooKeeper伺服器上開啟Super模式,方法是在ZooKeeper伺服器啟動的時候,添加如下系統屬性:

  • -Dzookeeper.DigestAuthenticationProvider.superDigest=foo:kWN6aNSbjcKWPqjiV7cg0N24raU=

        其中,“foo”代表了一個超級管理者的使用者名;“kWN6aNSbjcKWPqjiV7cg0N24raU=”是可變的,由ZooKeeper的系統管理者來進行自主配置,此例中使用的是“foo:zk-book”的編碼。完成對ZooKeeper伺服器的Super模式的開啟後,就可以在應用程式中使用了,下面是一個使用超級管理者權限操作ZooKeeper資料節點的示例程式。

public class AuthSample_Super {

    final static String PATH = "/zk-book";

    public static void main(String[] args) throws Exception {

        ZooKeeper zooKeeper1 = new ZooKeeper("127.0.0.1:2181", 5000, null);

        zooKeeper1.addAuthInfo("digest", "foo:true".getBytes());

        // 判斷是否為空

        if (zooKeeper1.exists(PATH, false) == null) {

            zooKeeper1.create(PATH, "init".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL);

        }

        // 用管理者權限

        ZooKeeper zooKeeper2 = new ZooKeeper("127.0.0.1:2181", 500000, null);

        zooKeeper2.addAuthInfo("digest", "foo:zk-book".getBytes());

        System.out.println(zooKeeper2.getData(PATH, false, null));

        // 用其他使用者通路

        ZooKeeper zooKeeper3 = new ZooKeeper("127.0.0.1:2181", 50000, null);

        zooKeeper3.addAuthInfo("digest", "foo:false".getBytes());

        System.out.println(zooKeeper3.getData(PATH, false, null));

    }

}

        從上面的輸出結果中,我們可以看出,由于“foo:zk-book”是一個超級管理者賬戶,是以能夠針對一個受權限控制的資料節點zk-book随意進行操作,但是對于“foo:false”這個普通使用者,就無法通過權限校驗了。

繼續閱讀