published on

managing samba shares with salt

Since I attended SaltConf, I had all sorts of motivation to help out with the https://github.com/saltstack-formulas, which I did.

I’ve found out that my brain, and work environment, does not always lend itself to that. For certain states (or a combination of states) to work, but also be decoupled from each other, I can’t always easily create a one-off git repo that is self contained.

We manage a few (5) sizable Samba servers (>20TB). Like it or not, we are a heavy Windows environment, and our order and image processing relies heavily upon said OS, and more importantly, UNC file path.

Aside from the names, the configuration is nearly identical across all shares (at the top level at least) so its fairly simple to templates this out.

What this state will do, is on a targeted system, it will loop through the pillar dictionary for ‘shares’, and create a file called: etc/smb.conf.d/share-name.conf

In our main smb.conf, we have a simple Include directive:

include={{ "{{ pillar.etc_prefix "}}}}/smb.conf.local

That file, smb.conf.local, is generated with simple cmd.run:

create-smb-conf-local:
   cmd:
      - run
      - names:
         - cat {{ "pillar.etc_prefix "}}}}/smb.conf.d/* > {{ "{{ pillar.etc_prefix "}}}}/smb.conf.local

When a “share” is added, the create-smb-conf-local is called to re-generate the included smb.conf.local file.

You can see the fill Samba state in my previous post, /2013/12/active-directory-authentication-with-salt/#samba-state.

Pillar Data

A pillar for shares should look like this:

shares:
 - Public
 - Private
 - Department

Salt State

I call this ‘shares’, and I have an open JIRA issue for myself to merge this into the samba state but we’ll keep is as simple as it is:

shares/
├── init.sls
└── share.conf.jinja

Its nice and flat, nothing scary here

Shares Init

include:
  - samba
{{ "{% for share in pillar.shares " }}%}
{{ "{{ pillar.etc_prefix " }}}}/smb.conf.d/{{" {{ share "}}}}:
  file.managed:
    - source: salt://shares/share.conf.jinja
    - template: jinja
    - context:
      share: {{ share }}
    - use:
      cmd: create-smb-conf-local
{{ "{% endfor " }}%}

Shares Jinja Template

[{{ "{{ share "}}}}]
 path = /data/{{ "{{ share "}}}}
 admin users = @"domain admins"
 map acl inherit = yes
 inherit acls = yes
 browseable = yes
 public = yes
 writable = yes
 inherit permissions = yes
 posix locking = yes
 nt acl support = yes
 create mask = 0775
 directory mask = 0775
 strict locking = no
 store dos attributes = yes
 csc policy = disable

 inherit acls = Yes

 map archive = No
 map readonly = no
 vfs objects = zfsacl full_audit
 nfs4:mode = special
 nfs4:acedup = merge
 nfs4:chown = yes

 ## ACL inheritance is done by ZFS
 inherit acls = no
 ## Avoid chmod(2) that breaks ACL
 inherit permissions = no
 force create mode = 00000
 force security mode = 00000
 force directory mode = 00000
 force directory security mode = 00000
 store dos attributes = yes
 ## ZFS ACL implements "write_acl" and "write_owner" permissions that
 ## is compatible with Windows (NT) ACL better than "dos filemode = yes"
 dos filemode = no

 full_audit:prefix = %u|%I|%m|%S
 full_audit:success = mkdir rename unlink rmdir
 full_audit:failure = none
 full_audit:facility = local7
 full_audit:priority = NOTICE

Final Results

So what does that look like?

share files:

smb.conf.d
|-- 000.globals
|-- Public
|-- Private
|-- Department
`-- keepme

[Private]
 path = /data/Private
 admin users = @"domain admins"
 map acl inherit = yes
 inherit acls = yes
 browseable = yes
 public = yes
 writable = yes
 inherit permissions = yes
 posix locking = yes
 nt acl support = yes
 create mask = 0775
 directory mask = 0775
 strict locking = no
 store dos attributes = yes
 csc policy = disable

 inherit acls = No 
 #inherit owner = Yes
 
 map archive = No
 map readonly = no
 vfs objects = zfsacl full_audit
 nfs4:mode = special
 nfs4:acedup = merge
 nfs4:chown = yes

 ## ACL inheritance is done by ZFS
 inherit acls = no
 ## Avoid chmod(2) that breaks ACL
 inherit permissions = no
 force create mode = 00000
 force security mode = 00000
 force directory mode = 00000
 force directory security mode = 00000
 store dos attributes = yes
 ## ZFS ACL implements "write_acl" and "write_owner" permissions that
 ## is compatible with Windows (NT) ACL better than "dos filemode = yes"
 dos filemode = no

 full_audit:prefix = %u|%I|%m|%S
 full_audit:success = mkdir rename unlink rmdir
 full_audit:failure = none
 full_audit:facility = local7
 full_audit:priority = NOTICE

ZFS is not a requirement, but you may noticed I load the zfsacl module, so in is in this use-case. I don’t manage any non-ZFS CIFS servers at this point so it works for me.

Along with ACL’s, we enable some amount of logging. This is super handy if you also have a tool like Splunk, and you can easily watch the life of an Order in real time.