Skip to content

Conversation

@smengcl
Copy link
Contributor

@smengcl smengcl commented Jan 24, 2022

https://issues.apache.org/jira/browse/HDDS-6214

Goal: Pass the correct user principal from the client to KMS to get the correct DEK.

Before this patch, in multi-tenancy, accessId is passed to KMS as the user name rather than the actual user principal (which is not desired).

Testing

  • Tested manually, see the instructions and results below.

Manual testing with Ranger KMS

Deployment and Configuration

  1. Deploy an Ozone + Ranger KMS cluster with security enabled
  2. Log in to Ranger Web UI as keyadmin user, edit the policy (or add a new policy) to grant systest user Create, Get Metadata, Generate EEK and Decrypt EEK permission for the purpose of this test. Save and log out.
  3. IMPORTANT. Make sure to add the following config to Ranger KMS's kms-site.xml (or core-site.xml, as long as the KMS would pick it up) to allow s3g (assuming this is the login user of S3 Gateway) to impersonate other users when its talking to the KMS:
<property>
  <name>hadoop.kms.proxyuser.s3g.users</name>
  <value>*</value>
</property>

<property>
  <name>hadoop.kms.proxyuser.s3g.hosts</name>
  <value>*</value>
</property>

In a production cluster, the value for hadoop.kms.proxyuser.s3g.hosts shall be limited to the S3G host only for better security. i.e. https://github.com/apache/ozone/blob/cef8bf5/hadoop-hdds/docs/content/security/SecuringTDE.md?plain=1#L109

hadoop.kms.proxyuser.s3g.users could also be limited to the users that would use S3 Gateway.

Be sure to restart the Ranger KMS after making the config change to take effect.

Commands

Set up a test tenant

kinit as an Ozone admin (om user in this case)

$ kinit -kt /cdep/keytabs/om.keytab om

$ ozone tenant create tenant1 --om-service-id=ozone1
22/02/01 23:00:00 INFO rpc.RpcClient: Creating Tenant: 'tenant1', with new volume: 'tenant1'
Created tenant 'tenant1'.

$ ozone tenant user assign systest --tenant=tenant1 --om-service-id=ozone1
Assigned 'systest' to 'tenant1' with accessId 'tenant1$systest'.
export AWS_ACCESS_KEY_ID='tenant1$systest'
export AWS_SECRET_ACCESS_KEY='<RETURNED_GENERATED_SHA256_ACCESS_KEY>'

Create an encrypted bucket

kinit as a regular user (systest user in this case)

$ kinit -kt /cdep/keytabs/systest.keytab systest

$ hadoop key create encKey
...
encKey has been successfully created with options Options{cipher='AES/CTR/NoPadding', bitLength=128, description='null', attributes=null}.
org.apache.hadoop.crypto.key.kms.LoadBalancingKMSClientProvider@434a63ab has been updated.

$ ozone sh bucket create -k encKey --layout=FILE_SYSTEM_OPTIMIZED /tenant1/encrypted-bucket1
22/02/01 23:29:36 INFO rpc.RpcClient: Creating Bucket: tenant1/encrypted-bucket1, with systest as owner and Versioning false and Storage Type set to DISK and Encryption set to true

Note that we can only create encrypted buckets via OzoneShell for now, and --layout=FILE_SYSTEM_OPTIMIZED is required here if we want to use HCFS (ofs / o3fs) to access the bucket (because the default layout is OBJECT_STORE for now, and it will break HCFS access).

Run ozone sh bucket info to confirm the DEKs (data encryption keys actually used to encrypt each file, which also differs for every file) in the bucket will be encrypted by the key name in encryptionKeyName field:

$ ozone sh bucket info /tenant1/encrypted-bucket1
{
  "metadata" : { },
  "volumeName" : "tenant1",
  "name" : "encrypted-bucket1",
  "storageType" : "DISK",
  "versioning" : false,
  "usedBytes" : 805306368,
  "usedNamespace" : 1,
  "creationTime" : "2022-02-01T23:29:36.926Z",
  "modificationTime" : "2022-02-01T23:29:36.926Z",
  "encryptionKeyName" : "encKey",
  "quotaInBytes" : -1,
  "quotaInNamespace" : -1,
  "bucketLayout" : "FILE_SYSTEM_OPTIMIZED",
  "owner" : "systest",
  "link" : false
}

Ozone Shell access

$ vim file1.txt
# this is test file1

$ ozone sh key put /tenant1/encrypted-bucket1/file1.txt file1.txt
...

We can run ozone sh key info to confirm that the key is encrypted. It should print the IV and EDEK (encryptedDataEncryptionKey) of this key.

$ ozone sh key info /tenant1/encrypted-bucket1/file1.txt
{
  "volumeName" : "tenant1",
  "bucketName" : "encrypted-bucket1",
  "name" : "file1.txt",
  "dataSize" : 15,
  "creationTime" : "2022-02-01T23:34:22.062Z",
  "modificationTime" : "2022-02-01T23:34:27.373Z",
  "replicationConfig" : {
    "replicationFactor" : "THREE",
    "requiredNodes" : 3,
    "replicationType" : "RATIS"
  },
  "ozoneKeyLocations" : [ {
    "containerID" : 4,
    "localID" : 109611004723200011,
    "length" : 15,
    "offset" : 0,
    "keyOffset" : 0
  } ],
  "metadata" : { },
  "fileEncryptionInfo" : {
    "cipherSuite" : "AES_CTR_NOPADDING",
    "iv" : "WWdijCnKdz9vu/PPuFAR4A==",
    "keyName" : "encKey",
    "ezKeyVersionName" : "orMslQ2AuxFLRCV0kAgDFv51HWyZm5KHanH4U4sW5Du",
    "encryptedDataEncryptionKey" : "RUxfXOmy/LAr0auDFZurbw==",
    "cryptoProtocolVersion" : "ENCRYPTION_ZONES"
  },
  "replicationType" : "RATIS",
  "replicationFactor" : 3
}

File retrieval via Ozone Shell should work, as expected:

$ ozone sh key cat /tenant1/encrypted-bucket1/file1.txt
...
this is test file1

S3 API access via S3 Gateway

Here we use AWS CLI to perform the testing, other S3 API compatible clients should also work seamlessly.

Install AWS CLI
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
$ aws --version
aws-cli/2.4.15 Python/3.8.8 Linux/3.10.0-1062.el7.x86_64 exe/x86_64.centos.7 prompt/off
Configure Access Key and Secret
$ aws configure
AWS Access Key ID [None]: tenant1$systest
AWS Secret Access Key [None]: <RETURNED_GENERATED_SHA256_ACCESS_KEY>
Default region name [None]:
Default output format [None]:
Testing S3API

Optionally, we are defining an alias first to reduce the clutter in the AWS CLI command. If the S3 Gateway endpoint enables HTTPS and its certificate is not signed by a trusted CA, you will need to specify the CA bundle to pass the certiticate check.

$ alias aws3='aws s3api --ca-bundle /var/lib/cloudera-scm-agent/agent-cert/cm-auto-global_cacerts.pem --endpoint https://s3g-host1.com:9879'

Reading the file1 we uploaded earlier via Ozone Shell:

$ aws3 list-buckets
{
    "Buckets": [
        {
            "Name": "encrypted-bucket1",
            "CreationDate": "2022-02-01T23:29:36.926000+00:00"
        }
    ]
}

$ aws3 list-objects --bucket encrypted-bucket1
{
    "Contents": [
        {
            "Key": "file1.txt",
            "LastModified": "2022-02-01T23:34:27.373000+00:00",
            "ETag": "2022-02-01T23:34:27.373Z",
            "Size": 15,
            "StorageClass": "STANDARD"
        }
    ]
}

$ aws3 get-object --bucket encrypted-bucket1 --key file1.txt file1-get.txt
{
    "AcceptRanges": "bytes",
    "LastModified": "2022-02-01T23:34:27+00:00",
    "ContentLength": 15,
    "CacheControl": "no-cache",
    "ContentType": "application/octet-stream",
    "Expires": "2022-02-01T23:59:46+00:00",
    "Metadata": {}
}

$ cat file1-get.txt
this is test file1

Put a new file via S3 Gateway, then get it back:

$ vim file2.txt
# this is test file42

$ aws3 put-object --bucket encrypted-bucket1 --key file2.txt --body file2.txt

$ aws3 list-objects --bucket encrypted-bucket1
{
    "Contents": [
        {
            "Key": "file1.txt",
            "LastModified": "2022-02-01T23:34:27.373000+00:00",
            "ETag": "2022-02-01T23:34:27.373Z",
            "Size": 15,
            "StorageClass": "STANDARD"
        },
        {
            "Key": "file2.txt",
            "LastModified": "2022-02-02T00:01:27.363000+00:00",
            "ETag": "2022-02-02T00:01:27.363Z",
            "Size": 20,
            "StorageClass": "STANDARD"
        }
    ]
}

$ aws3 get-object --bucket encrypted-bucket1 --key file2.txt file2-get.txt
{
    "AcceptRanges": "bytes",
    "LastModified": "2022-02-02T00:01:27+00:00",
    "ContentLength": 20,
    "CacheControl": "no-cache",
    "ContentType": "application/octet-stream",
    "Expires": "2022-02-02T00:02:53+00:00",
    "Metadata": {}
}

$ cat file2-get.txt
this is test file42

This concludes the multi-tenancy manual testing with KMS encryption on the bucket via Ozone Shell and S3 API.

Change-Id: Ifd842b379a05e929c5457e83d1c65e7cb8857a15
Change-Id: If68c79168c2292f05efdbeb63188a31b5ba5dd4c
Change-Id: Id00546aabb070398aad9438a21f9ee5b1311d8c7
Change-Id: I80b178bd3f29b1a691e62eb16e026347f5000390
Copy link
Contributor

@prashantpogde prashantpogde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments and nitpicks.

Change-Id: I993d05598f3ea66ac1819934ab5c5a94b9e50c70
@prashantpogde
Copy link
Contributor

Thanks @smengcl. Looks good to me.. Can you please also update the PR with the manual testing steps with KMS setup? That would be helpful

@smengcl
Copy link
Contributor Author

smengcl commented Feb 2, 2022

Thanks @smengcl. Looks good to me.. Can you please also update the PR with the manual testing steps with KMS setup? That would be helpful

Done. One should be able to follow the steps above to make encrypted buckets work with multi-tenancy.

Copy link
Contributor

@errose28 errose28 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this @smengcl. Some comments inline.

…lumeResponse` -> `GetS3VolumeInfoResponse`.

Change-Id: Ie78d21ba242d1b176b3d11e7cc469d16e1da7599
…ass.

Change-Id: I61edd834067e53b2aef9bcfdbbb7647a1288ec49
…eTenant`.

Change-Id: I18e1ff588b26aa973afcc5dc580b5e95af400a4f
@smengcl
Copy link
Contributor Author

smengcl commented Feb 4, 2022

Also triggered a CI in my fork on a branch that has HDDS-6239 applied:
https://github.com/smengcl/hadoop-ozone/commits/HDDS-6214-CI

Change-Id: I6859133b2f72971f0b68ea8116f4b539c484445d
@smengcl
Copy link
Contributor Author

smengcl commented Feb 8, 2022

Renamed S3VolumeInfo (along with related method names) to S3VolumeContext per @avijayanhwx 's request.

Triggered proper CI here: https://github.com/smengcl/hadoop-ozone/commits/HDDS-6214-CI-2

@smengcl
Copy link
Contributor Author

smengcl commented Feb 9, 2022

CI passed on my fork.

Copy link
Contributor

@errose28 errose28 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates @smengcl. Looks like the name of the response proto got updated but the corresponding request proto did not. Other than that the rest of the changes look good.

…VolumeContext

Change-Id: Ic54e8e1e854721503526db2507e31bd62fe3791d
Change-Id: Ib4f72918f86c289ad209387d9b1214fb3c183513
@smengcl
Copy link
Contributor Author

smengcl commented Feb 14, 2022

Copy link
Contributor

@errose28 errose28 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick updates @smengcl. LGTM +1.

@smengcl
Copy link
Contributor Author

smengcl commented Feb 15, 2022

Thanks @errose28 and @prashantpogde for reviewing this.

@smengcl smengcl merged commit 2e6754f into apache:HDDS-4944 Feb 15, 2022
errose28 added a commit to errose28/ozone that referenced this pull request Mar 30, 2022
* HDDS-4944: (268 commits)
  HDDS-6366. [Multi-Tenant] Disallow specifying custom accessId in OzoneManager (apache#3166)
  HDDS-6275. [Multi-Tenant] Add feature documentation and CLI quick start guide (apache#3095)
  HDDS-6063. [Multi-Tenant] Use VOLUME_LOCK in read and write requests, and some minor refactoring (apache#3051)
  HDDS-6214. [Multi-Tenant] Fix KMS Encryption/Decryption (apache#3010)
  HDDS-6322. Fix Recon getting inccorrect sequenceNumber from OM (apache#3090)
  HDDS-5913. Avoid integer overflow when setting dfs.container.ratis.lo… (apache#2785)
  HDDS-6313. Remove replicas in ContainerStateMap when a container is deleted (apache#3086)
  HDDS-6186. Selective checks: skip integration check for unit test changes (apache#3061)
  HDDS-6310. Update json-smart to 2.4.7. (apache#3080)
  HDDS-6190. Cleanup unnecessary datanode id path checks. (apache#2993)
  HDDS-6304. Add enforcer to make sure ozone.version equals project.version (apache#3075)
  HDDS-6309. Update ozone-runner version to 20220212-1 (apache#3079)
  HDDS-6293. Allow using custom ozone-runner image (apache#3072)
  HDDS-4126. Freon key generator should support >2GB files. (apache#3054)
  HDDS-6088. Implement O3FS/OFS getFileChecksum() using file checksum helpers - addendum: fix checkstyle
  HDDS-6088. Implement O3FS/OFS getFileChecksum() using file checksum helpers. (apache#2935)
  HDDS-6084. [Multi-Tenant] Handle upgrades to version supporting S3 multi-tenancy (apache#3018)
  HDDS-6257. Wrong stack trace for S3 errors (apache#3066)
  HDDS-6278 Improve memory profile for listStatus API call. (apache#3053)
  HDDS-6285. ozonesecure-mr intermittently failing with timeout downloading packages (apache#3057)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants