]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
Validate bucket names as per revised s3 spec 26787/head
authorSoumya Koduri <skoduri@redhat.com>
Wed, 6 Mar 2019 12:28:32 +0000 (17:58 +0530)
committerSoumya Koduri <skoduri@redhat.com>
Thu, 8 Aug 2019 11:24:12 +0000 (16:54 +0530)
As per amazon s3 spec -
https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html

* The s3 bucket names should not contain upper case letters or underscore.
* Name cannot end with dash or have consecutive periods, or dashes adjacent
  to periods.
* Each label in the bucket name must start and end with a lowercase
  letter or a number.
* Name cannot exceed 63 characters.

This change is to enforce these rules if rgw_relaxed_s3_bucket_names is set to
'false' which is by default.

Fixes: https://tracker.ceph.com/issues/36293
Signed-off-by: Soumya Koduri <skoduri@redhat.com>
PendingReleaseNotes
doc/radosgw/s3/bucketops.rst
qa/suites/rgw/multifs/tasks/rgw_bucket_quota.yaml
qa/suites/rgw/multifs/tasks/rgw_multipart_upload.yaml
qa/suites/rgw/multifs/tasks/rgw_user_quota.yaml
qa/suites/rgw/thrash/workload/rgw_bucket_quota.yaml
qa/suites/rgw/thrash/workload/rgw_multipart_upload.yaml
qa/suites/rgw/thrash/workload/rgw_user_quota.yaml
qa/tasks/radosgw_admin_rest.py
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h

index 851dba5b81b214e5bac856d6e9c2f80da84c8197..6f17a6250c00d77a8afff6a494b5c6878430f7de 100644 (file)
   objects and the other deletes them. Read the troubleshooting section
   of the dynamic resharding docs for details.
 
+* RGW: Bucket naming restrictions have changed and likely to cause
+  InvalidBucketName errors. We recommend to set ``rgw_relaxed_s3_bucket_names``
+  option to true as a workaround.
+
 * In the Zabbix Mgr Module there was a typo in the key being send
   to Zabbix for PGs in backfill_wait state. The key that was sent
   was 'wait_backfill' and the correct name is 'backfill_wait'.
index 0ebfc7fbb10c5e97633d2e98bfd62835fae1ce10..ffa14e8950d7b1f0f2e12043d890174d31379fe7 100644 (file)
@@ -12,8 +12,13 @@ Constraints
 In general, bucket names should follow domain name constraints.
 
 - Bucket names must be unique.
-- Bucket names must begin and end with a lowercase letter.
-- Bucket names may contain a dash (-).
+- Bucket names cannot be formatted as IP address.
+- Bucket names can be between 3 and 63 characters long.
+- Bucket names must not contain uppercase characters or underscores.
+- Bucket names must start with a lowercase letter or number.
+- Bucket names must be a series of one or more labels. Adjacent labels are separated by a single period (.). Bucket names can contain lowercase letters, numbers, and hyphens. Each label must start and end with a lowercase letter or a number.
+
+.. note:: The above constraints are relaxed if the option 'rgw_relaxed_s3_bucket_names' is set to true except that the bucket names must still be unique, cannot be formatted as IP address and can contain letters, numbers, periods, dashes and underscores for up to 255 characters long.
 
 Syntax
 ~~~~~~
index c518d0e14caff4a5112e2a42cc7089dc7a37d954..eb4a67ea0aa5f6e80a9bdb4c9322b1d085fde80f 100644 (file)
@@ -8,3 +8,8 @@ tasks:
     clients:
       client.0:
         - rgw/s3_bucket_quota.pl
+overrides:
+  ceph:
+    conf:
+      client:
+        rgw relaxed s3 bucket names: true
index b042aa80c65b724f45306bd412e546fb2c4f1bf3..f7e561f073182c19300cc0f5fe5807e7b1ed9af5 100644 (file)
@@ -8,3 +8,8 @@ tasks:
     clients:
       client.0:
         - rgw/s3_multipart_upload.pl
+overrides:
+  ceph:
+    conf:
+      client:
+        rgw relaxed s3 bucket names: true
index ef9d6df110e6ea6308b3ce3c872927fc00e1d4b5..e661ff33d101b56412dba157a5a56651931da049 100644 (file)
@@ -8,3 +8,8 @@ tasks:
     clients:
       client.0:
         - rgw/s3_user_quota.pl
+overrides:
+  ceph:
+    conf:
+      client:
+        rgw relaxed s3 bucket names: true
index 32e6af59f91b3aec7c42ab1167bb908c52b2277a..eef9ca3ec653635010d75967a13b38c4a6189987 100644 (file)
@@ -5,3 +5,8 @@ tasks:
     clients:
       client.0:
         - rgw/s3_bucket_quota.pl
+overrides:
+  ceph:
+    conf:
+      client:
+        rgw relaxed s3 bucket names: true
index b792336d5b5c8e1100bc2ea9ba86c2f37f686b53..f364f2d23bd02be93a4e7cbb88a6bced66ad1787 100644 (file)
@@ -5,3 +5,8 @@ tasks:
     clients:
       client.0:
         - rgw/s3_multipart_upload.pl
+overrides:
+  ceph:
+    conf:
+      client:
+        rgw relaxed s3 bucket names: true
index 0a9888276feaeae05d0ff2a981d4718ffa1ba2d7..670ac0c170a82599a0c6138d65375527d0f1f286 100644 (file)
@@ -5,3 +5,8 @@ tasks:
     clients:
       client.0:
         - rgw/s3_user_quota.pl
+overrides:
+  ceph:
+    conf:
+      client:
+        rgw relaxed s3 bucket names: true
index 12d3ac046cfc8570c5687da239273a7bd2dbd2ed..5d8bf18687b3515f5b0cc482a5a3e8d5a057cdfb 100644 (file)
@@ -549,7 +549,7 @@ def task(ctx, config):
     assert out['usage']['rgw.main']['num_objects'] == 0
 
     # create a bucket for deletion stats
-    useless_bucket = connection.create_bucket('useless_bucket')
+    useless_bucket = connection.create_bucket('useless-bucket')
     useless_key = useless_bucket.new_key('useless_key')
     useless_key.set_contents_from_string('useless string')
 
index 95896f20e3fd9ab2cd2a334babcf68e8ccc868ab..e306a3cfacf238868b95ada56be7f79ae307e10e 100644 (file)
@@ -1547,8 +1547,13 @@ public:
 int RGWCreateBucket_ObjStore_S3::get_params()
 {
   RGWAccessControlPolicy_S3 s3policy(s->cct);
+  bool relaxed_names = s->cct->_conf->rgw_relaxed_s3_bucket_names;
+  int r = valid_s3_bucket_name(s->bucket_name, relaxed_names);
+  if (r)
+    return r;
 
-  int r = create_s3_policy(s, store, s3policy, s->owner);
+  r = create_s3_policy(s, store, s3policy, s->owner);
   if (r < 0)
     return r;
 
@@ -3907,7 +3912,6 @@ static int verify_mfa(RGWRados *store, RGWUserInfo *user, const string& mfa_str,
 int RGWHandler_REST_S3::postauth_init()
 {
   struct req_init_state *t = &s->init_state;
-  bool relaxed_names = s->cct->_conf->rgw_relaxed_s3_bucket_names;
 
   rgw_parse_url_bucket(t->url_bucket, s->user->user_id.tenant,
                      s->bucket_tenant, s->bucket_name);
@@ -3920,9 +3924,6 @@ int RGWHandler_REST_S3::postauth_init()
   if (ret)
     return ret;
   if (!s->bucket_name.empty()) {
-    ret = valid_s3_bucket_name(s->bucket_name, relaxed_names);
-    if (ret)
-      return ret;
     ret = validate_object_name(s->object.name);
     if (ret)
       return ret;
@@ -3934,9 +3935,6 @@ int RGWHandler_REST_S3::postauth_init()
     ret = rgw_validate_tenant_name(s->src_tenant_name);
     if (ret)
       return ret;
-    ret = valid_s3_bucket_name(s->src_bucket_name, relaxed_names);
-    if (ret)
-      return ret;
   }
 
   const char *mfa = s->info.env->get("HTTP_X_AMZ_MFA");
@@ -3957,11 +3955,7 @@ int RGWHandler_REST_S3::init(RGWRados *store, struct req_state *s,
   ret = rgw_validate_tenant_name(s->bucket_tenant);
   if (ret)
     return ret;
-  bool relaxed_names = s->cct->_conf->rgw_relaxed_s3_bucket_names;
   if (!s->bucket_name.empty()) {
-    ret = valid_s3_bucket_name(s->bucket_name, relaxed_names);
-    if (ret)
-      return ret;
     ret = validate_object_name(s->object.name);
     if (ret)
       return ret;
index d87d69c7f321abca05671720b3bf4b2ff9fc9f91..f2e66673e77c643cd456ed449c7395bfc480cc96 100644 (file)
@@ -747,15 +747,17 @@ static inline int valid_s3_bucket_name(const string& name, bool relaxed=false)
   // This function enforces Amazon's spec for bucket names.
   // (The requirements, not the recommendations.)
   int len = name.size();
+  int max = (relaxed ? 255 : 63);
+
   if (len < 3) {
     // Name too short
     return -ERR_INVALID_BUCKET_NAME;
-  } else if (len > 255) {
+  } else if (len > max) {
     // Name too long
     return -ERR_INVALID_BUCKET_NAME;
   }
 
-  // bucket names must start with a number, letter, or underscore
+  // bucket names must start with a number or letter
   if (!(isalpha(name[0]) || isdigit(name[0]))) {
     if (!relaxed)
       return -ERR_INVALID_BUCKET_NAME;
@@ -763,14 +765,44 @@ static inline int valid_s3_bucket_name(const string& name, bool relaxed=false)
       return -ERR_INVALID_BUCKET_NAME;
   }
 
+  // bucket names must end with a number or letter
+  if (!(isalpha(name[len-1]) || isdigit(name[len-1])))
+    if (!relaxed)
+      return -ERR_INVALID_BUCKET_NAME;
+
   for (const char *s = name.c_str(); *s; ++s) {
     char c = *s;
-    if (isdigit(c) || (c == '.'))
-      continue;
-    if (isalpha(c))
+    if (isdigit(c))
       continue;
-    if ((c == '-') || (c == '_'))
+
+    if (isalpha(c)) {
+      // name cannot contain uppercase letters
+      if (relaxed || islower(c))
+       continue;
+    }
+
+    if (c == '_')
+      // name cannot contain underscore
+      if (relaxed)
+       continue;
+
+    if (c == '-')
       continue;
+
+    if (c == '.') {
+      if (!relaxed && s && *s) {
+       // name cannot have consecutive periods or dashes
+       // adjacent to periods
+       // ensure s is neither the first nor the last character
+       char p = *(s-1);
+       char n = *(s+1);
+       if ((p != '-') && (n != '.') && (n != '-'))
+         continue;
+      } else {
+       continue;
+      }
+    }
+
     // Invalid character
     return -ERR_INVALID_BUCKET_NAME;
   }