curator-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Robert Kanter <rkan...@cloudera.com>
Subject Re: Help with ACLProvider + Kerberos
Date Thu, 07 Nov 2013 23:51:21 GMT
Are you sure that this is something my ACLProvider has to handle?  My
understanding is that the ACLProvider is a fairly “dumb” object that other
code is supposed to simply use to get the ACLs to apply when creating
znodes.  The ACLProvider interface only has two methods:
public List<ACL> getDefaultAcl();
public List<ACL> getAclForPath(String path);
So there’s nothing in here about protection mode.

I think whatever code is changing the GUID-prefixed path into the
originally-named path (this does happen because when I browse the znodes
using ZKCli.sh it has “/foo” and not the prefixed one) needs to be checking
with the ACLProvider, and its not.  I tried looking around the Curator
code, but I wasn’t able to find what does this.  Do you know?


- Robert



On Thu, Nov 7, 2013 at 3:40 PM, Jordan Zimmerman <jordan@jordanzimmerman.com
> wrote:

> Yes, this is called "protection" mode. I'll paste the details from the
> Javadoc below. The TL;DR is that this is required when using
> sequential/ephemeral with ZooKeeper. So, your ACLProvider needs to be able
> to handle this.
>
> -Jordan
>
> from create().withProtection():
>
> It turns out there is an edge case that exists when creating
> sequential-ephemeral nodes. The creation can succeed on the server, but the
> server can crash before the created node name is returned to the client.
> However, the ZK session is still valid so the ephemeral node is not
> deleted. Thus, there is no way for the client to determine what node was
> created for them.
> Even without sequential-ephemeral, however, the create can succeed on the
> sever but the client (for various reasons) will not know it.
>
> Putting the create builder into protection mode works around this. The
> name of the node that is created is prefixed with a GUID. If node creation
> fails the normal retry mechanism will occur. On the retry, the parent path
> is first searched for a node that has the GUID in it. If that node is
> found, it is assumed to be the lost node that was successfully created on
> the first try and is returned to the caller.
>
> On Nov 7, 2013, at 1:13 PM, Robert Kanter <rkanter@cloudera.com> wrote:
>
> I did some more investigating on this issue.  It looks like when you
> acquire a lock, it creates the path by doing:
> ourPath =
> client.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);
> When I do that manually where path is “/foo”, it actually doesn’t create
> “/foo” yet and instead creates something like
> "/_c_2235fc7d-f5e8-4c3a-bb24-27c610022aaa-foo0000000000”.
>
> From what I can tell, this has to do with the withprotection() and
> EPHEMERAL_SEQUENTIAL mode and is to prevent some kind of problem I don’t
> quite understand from the javadocs.  In any case, I believe that something
> eventually must rename
> "/_c_2235fc7d-f5e8-4c3a-bb24-27c610022aaa-foo0000000000” to “/foo”.  When I
> checked, "/_c_2235fc7d-f5e8-4c3a-bb24-27c610022aaa-foo0000000000” has the
> ACLs I set in the ACLProvider, so I’m thinking the problem must be
> happening when the znode is renamed.  I’m not sure where/when that happens,
> but I’d guess its not using the ACLProvider and that’s why “/foo" has the
> default ACLs.
>
> Do you think this is the cause?  Any idea on how to fix it or workaround
> it?
>
> thanks
> - Robert
>
>
>
> On Tue, Nov 5, 2013 at 1:58 PM, Robert Kanter <rkanter@cloudera.com>wrote:
>
>> I created the below test class using JUnit.  It starts a TestingServerand connects
to it; then it creates a path directly to verify that the
>> custom ACLProvider is being applied.  Then it tries to do the same with
>> an InterProcessReadWriteLock and fails the test because its using the
>> default ACLs.  I used “ip” instead of “sasl” to keep things simpler.
>>
>> I did take a quick look at the Curator code and it seemed to be using the
>> ACLProvider through the CuratorFramework when using locks, but perhaps I
>> missed something (and I’m not super familiar with the codebase).
>>
>> Please take a look; thanks!
>> - Robert
>>
>>
>> import java.util.Collections;
>> import java.util.List;
>> import junit.framework.TestCase;
>> import org.apache.curator.RetryPolicy;
>> import org.apache.curator.framework.CuratorFramework;
>> import org.apache.curator.framework.CuratorFrameworkFactory;
>> import org.apache.curator.framework.api.ACLProvider;
>>  import org.apache.curator.framework.recipes.locks.InterProcessMutex;
>> import
>> org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
>> import org.apache.curator.retry.ExponentialBackoffRetry;
>> import org.apache.curator.test.TestingServer;
>> import org.apache.zookeeper.ZooDefs;
>> import org.apache.zookeeper.data.ACL;
>> import org.apache.zookeeper.data.Id<http://org.apache.zookeeper.data.id/>
>> ;
>>
>> public class TestLockACLs extends TestCase {
>>     private TestingServer zkServer;
>>     private CuratorFramework client;
>>     private final List<ACL> acls = Collections.singletonList(new
>> ACL(ZooDefs.Perms.ALL, new Id("ip", "127.0.0.1")));
>>
>>     @Override
>>     protected void setUp() throws Exception {
>>         super.setUp();
>>         zkServer = new TestingServer();
>>         createClient();
>>     }
>>
>>     @Override
>>     protected void tearDown() throws Exception {
>>         super.tearDown();
>>         client.close();
>>         zkServer.stop();
>>         zkServer.close();
>>     }
>>
>>     private void createClient() throws Exception {
>>         RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
>>         String zkConnectionString = zkServer.getConnectString();
>>         String zkNamespace = "ns";
>>         client = CuratorFrameworkFactory.builder()
>>                                             .namespace(zkNamespace)
>>
>> .connectString(zkConnectionString)
>>                                             .retryPolicy(retryPolicy)
>>                                             .aclProvider(new
>> MyACLProvider())
>>                                             .build();
>>         client.start();
>>     }
>>
>>     public void testLockACLs() throws Exception {
>>         // Create a path directly and verify that MyACLProvider is being
>> used
>>         client.create().forPath("/foo");
>>         assertNotNull(client.checkExists().forPath("/foo"));
>>         assertEquals(ZooDefs.Perms.ALL,
>> client.getACL().forPath("/foo").get(0).getPerms());
>>         assertEquals("ip",
>> client.getACL().forPath("/foo").get(0).getId().getScheme());
>>         assertEquals("127.0.0.1",
>> client.getACL().forPath("/foo").get(0).getId().getId());
>>
>>         // Now try creating a lock and we'll see that it incorrectly has
>> the default world ACLs
>>         // and doesn't seem to be using MyACLProvider
>>         InterProcessReadWriteLock lock = new
>> InterProcessReadWriteLock(client, "/bar");
>>         InterProcessMutex writeLock = lock.writeLock();
>>         writeLock.acquire();
>>         assertNotNull(client.checkExists().forPath("/bar"));
>>         assertEquals(ZooDefs.Perms.ALL,
>> client.getACL().forPath("/bar").get(0).getPerms());
>>         assertEquals("ip",
>> client.getACL().forPath("/bar").get(0).getId().getScheme());
>>         assertEquals("127.0.0.1",
>> client.getACL().forPath("/bar").get(0).getId().getId());
>>     }
>>
>>     public class MyACLProvider implements ACLProvider {
>>
>>         @Override
>>         public List<ACL> getDefaultAcl() {
>>             return acls;
>>         }
>>
>>         @Override
>>         public List<ACL> getAclForPath(String path) {
>>             return acls;
>>         }
>>     }
>> }
>>
>>
>> On Mon, Nov 4, 2013 at 6:10 PM, Jordan Zimmerman <
>> jordan@jordanzimmerman.com> wrote:
>>
>>> The ACLProvider should be called for every node created. It’s not
>>> getting called? Can you produce a test that shows this?
>>>
>>> -Jordan
>>>
>>> On Nov 4, 2013, at 5:57 PM, Robert Kanter <rkanter@cloudera.com> wrote:
>>>
>>> I have everything working now except for one thing:
>>> The ACLProvider doesn’t seem to be used for the locks (Curator’s
>>> InterProcessReadWriteLock); they are always created with the default
>>> fully open ACLs.  I know the ACLProvider is correct now because the
>>> service discovery is using it and znodes created by it have the correct
>>> ACLs.  InterProcessReadWriteLock’s constructor takes in the
>>> CuratorFramework object, which has the ACLProvider set.
>>>
>>> Any ideas?
>>> This sounds like it could be a Curator bug :(
>>> I’m not familiar with Curator’s codebase, but I’ll try to take a look
>>> and see if I can figure it out.
>>>
>>> thanks
>>> - Robert
>>>
>>>
>>>
>>> On Mon, Nov 4, 2013 at 1:09 PM, Robert Kanter <rkanter@cloudera.com>wrote:
>>>
>>>> I don’t have it 100% working yet, but I’ve figured out a lot more, so
I
>>>> thought I’d share in case anyone else runs into this:
>>>>
>>>> The ZooDefs.Ids.CREATOR_ALL_ACL predefined ACL that I was trying to
>>>> use is for the “auth” scheme.  For SASL/Kerberos, we want “sasl”.
 The
>>>> javadoc for the predefined one wasn’t very clear on that; I had to look
at
>>>> the code.  Using this is working:
>>>> Collections.singletonList(new ACL(Perms.ALL, new Id("sasl",
>>>> principal)));
>>>>
>>>> I was also able to find answers to the three questions I asked:
>>>> 1) Yes; looking through the code, its definitely grabbing the
>>>> ACLProvider and using it.
>>>> 2) Yes; I think the only way to do this is to recursively travel
>>>> through the znodes under /oozie and apply the ACL on starting up Oozie.
>>>> We should only have to do this if previously it was setup without
>>>> security and has since been reconfigured to use security; so we should only
>>>> have to do this once.  I can probably have a znode as a flag that
>>>> states if everything has ACLs or not to make it more efficient
>>>> 3) It doesn’t look like it; I’ll have to get the ZK client and do it
>>>> from outside Curator
>>>>
>>>>
>>>> - Robert
>>>>
>>>>
>>>> On Mon, Oct 28, 2013 at 5:47 PM, Jordan Zimmerman <
>>>> jordan@jordanzimmerman.com> wrote:
>>>>
>>>>> I don’t have any experience with this. Curator doesn’t do much -
it
>>>>> sets up the ACL as the CLI options dictate. I do know that you also have
to
>>>>> do work on the server side to make this work.
>>>>>
>>>>> -JZ
>>>>>
>>>>> On Oct 24, 2013, at 4:58 PM, Robert Kanter <rkanter@cloudera.com>
>>>>> wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> Is there any documentation on using an ACLProvider and/or Kerberos?
>>>>>
>>>>> From what I gathered at various sites, to use Kerberos, all I have to
>>>>> do is set the following properties before building the CuratorFramework
>>>>> client:
>>>>> System.setProperty("java.security.auth.login.config",
>>>>> "/path/to/jaasConfFile");
>>>>>
>>>>> System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
>>>>> System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
>>>>> "Client");
>>>>> Looking at the logs for the client and server, this appears to be
>>>>> working properly and my program is connecting to ZooKeeper using Kerberos.
>>>>>
>>>>> The problem I'm having is with the ACLs.
>>>>>
>>>>> I'd like to set the ACLs so that only the Kerberos user running the
>>>>> program can do anything.  From what I can tell, if I specify an
>>>>> ACLProvider, then Curator will automatically use it for setting ACLs
>>>>> on all paths.  So, an ACLProvider like the following should do what I
>>>>> want:
>>>>> public class CreatorACLProvider implements ACLProvider {
>>>>>    @Override
>>>>>     public List<ACL> getDefaultAcl() {
>>>>>         return ZooDefs.Ids.CREATOR_ALL_ACL;
>>>>>    }
>>>>>    @Override
>>>>>     public List<ACL> getAclForPath(String path) {
>>>>>         return ZooDefs.Ids.CREATOR_ALL_ACL;
>>>>>    }
>>>>> }
>>>>> Then I would just do this:
>>>>> client = CuratorFrameworkFactory.builder()
>>>>>                                 .namespace(zkNamespace)
>>>>>                                 .connectString(zkConnectionString)
>>>>>                                 .retryPolicy(retryPolicy)
>>>>>                                 .aclProvider(new CreatorACLProvider())
>>>>>                                 .build();
>>>>> client.start();
>>>>>
>>>>> However, this doesn't seem to be working.  The zkcli returns this (on
>>>>> a newly created znode):
>>>>> [zk: localhost:2181(CONNECTED) 8] getAcl
>>>>> /oozie/locks/0000000-131024162150146-oozie-oozi-W
>>>>> 'world,'anyone
>>>>> : Cdr.
>>>>> Is there something that I missed?
>>>>>
>>>>> A few other questions:
>>>>> 1) Will the ACLProvider cause the ACLs to be applied to znodes
>>>>> created by the Curator recipes?  (e.g. InterProcessReadWriteLock,
>>>>> ServiceDiscovery, etc).  If not, then how should I go about setting
>>>>> the ACLs for these znodes?
>>>>> 2) I'm guessing that the ACLProvider is only applied when creating
>>>>> the znode, right; so existing znodes from before I added the
>>>>> ACLProvider won't have the ACLs I want, right?  What would be the
>>>>> best way to apply the ACLs to any existing znodes that don't have it
set?
>>>>>  (My goal is to have all znodes under /oozie have the CREATOR_ALL_ACL)
>>>>> 3) Is there a way to set the ACLs on the namespace itself (i.e. /oozie)?
>>>>>  The methods that take a path (and automatically prepend the namespace)
>>>>> don't allow simply "/", so it seems like I'd have to use the
>>>>> ZooKeeper client directly to set ACLs manually on the namespace.  Or
would
>>>>> simply passing an empty string "" work?
>>>>>
>>>>> thanks
>>>>> - Robert
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>
>

Mime
View raw message