Problem Summary
Certain customers, on certain versions of Berkshelf and Chef Infra Server have been able to upload invalid versions of cookbooks a primary cookbook depends upon. Invalid means a cookbook version that is less than two or three digits, meaning a single digit with no periods like 1 or 10.
I used a dummy cookbook named testit to test the scenario. The testit cookbook version itself looks like this: 0.1.1
However testit, in its metadata.rb file depends on another cookbook named logrotate with a version specified like this, 1, which is an invalid version. Correct cookbook/dependency versions have two or three digits, separated by periods: 0.1 or 0.1.1
For more detail, see the note at https://docs.chef.io/cookbook_versioning/#constraints
Both clients like knife and Berkshelf and the server Infra Server itself have code intended to validate that incoming versions for both cookbooks and their dependencies are valid, but it looks like there is a loophole somewhere for the time being.
Consequences
When a cookbook/dependency of this nature is uploaded to a Chef Infra Server, it can prevent dependency resolution of cookbook runlists ENTIRELY.
Attempted Reproduction
To attempt a reproduction, I will use the same pattern: A cookbook with a good multi-digit version for itself, but a dependency reference in the same cookbook with a single digit version. I have a cookbook named testit
that I will use.
I used a version of Chef Server older than the one specified by the customer, because that is what I could get. An unmodified Berkshelf 7.0.10 or 7.0.8(I tested both with same result) behaves just as you would expect and rejects the attempted upload as shown
berks version
7.0.8
[root@chef-14 testit]# berks install
An error occurred while reading the Berksfile:
'3' does not match 'x.y.z' or 'x.y'
[root@chef-14 testit]# grep depends metadata.rb
depends 'logrotate', '= 3'
I then proceeded to mangle the Berkshelf 7.0.8 version validation so that it would accept single digit versions and attempt to pass those on to Chef Server. Berkshelf did send the request after I hacked it....
berks upload --no-ssl-verify
Skipping logrotate (3.0.0) (frozen)
E, [2021-09-09T00:54:01.939049 #2272] ERROR -- : Net::HTTPServerException: 400 "Bad Request"
E, [2021-09-09T00:54:01.939154 #2272] ERROR -- : /opt/chefdk/embedded/lib/ruby/2.5.0/net/http/response.rb:122:in `error!'
/opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/chef-14.14.29/lib/chef/http.rb:152:in `request'
/opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/chef-14.14.29/lib/chef/http.rb:123:in `put'
/opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/chef-14.14.29/lib/chef/cookbook_uploader.rb:103:in `block in upload_cookbooks'
There was an error connecting to the Chef Server
However, Chef Server rejected it with this in the /var/log/opscode/opscode-erchef/requests.log.1 which is fairly clear and required no tracing. The error message is saying "I found a dependency reference in the metdata,rb for the testit cookbook that only consisted of a single digit. This is invald, so I rejected the request with a 400 response code"
2021-09-09T04:54:01Z erchef@127.0.0.1 method=PUT; path=/organizations/delivery/cookbooks/testit/3.0.0; status=400; req_id=g3IAA2QAEGVyY2hlZkAxMjcuMC4wLjEDAAM2h3s8AAF84iGu; org_name=delivery; msg={ej_invalid,object_value,<<"metadata.dependencies">>,<<"= 3">>,string,string,<<"Invalid version constraint">>}; couchdb_groups=false; couchdb_organizations=false; couchdb_containers=false; couchdb_acls=false; 503_mode=false; couchdb_associations=false; couchdb_association_requests=false; req_time=2; rdbms_time=0; rdbms_count=1; user=mary-admin; req_api_version=2;
I cannot reproduce the conditions that lead up to the Chef Server actually accepting the request and storing the bad cookbook metadata.rb file
Reference: https://getchef.zendesk.com/agent/tickets/28684
Comments
0 comments
Article is closed for comments.