As cchooper observed, macros are expanded at compile time, not runtime. This means that they cannot see lexical variables like k. (Since x was a global variable, it could be seen at compile time, thus making your first example work.) In order to look at the lexical environment, you need an ordinary function:
(def assign (name expr)
(eval `(= ,name ',expr)))
The reason you don't need a macro here is that you aren't actually suppressing evaluation, which is what macros do; you want the values of name and expr. Thus, assign should be a function, which runs at runtime. Also note that expr needs to be quoted, or you attempt to evaluate it, which fails if it is a symbol.
The one thing that might trip you up with this function is that it (like =) will not create lexical variables, but only globals, unless lexicals of the names you are about to assign are already declared.
Also, a formatting tip: to get text to appear as code, surround it by blank lines and indent it by two spaces.